在for-in循环中键入cast

问题描述 投票:97回答:5

我有这个for-in循环:

for button in view.subviews {
}

现在我想将按钮转换为自定义类,以便我可以使用它的属性。

我试过这个:for button in view.subviews as AClass

但它不起作用,并给我一个错误:'AClass' does not conform to protocol 'SequenceType'

我试过这个:for button:AClass in view.subviews

但这也不起作用。

for-loop swift for-in-loop
5个回答
142
投票

对于Swift 2及更高版本:

Swift 2为for循环添加了case模式,这使得在for循环中输入类型变得更加容易和安全:

for case let button as AClass in view.subviews {
    // do something with button
}

为什么这比你在Swift 1.2及更早版本中做的更好?因为案例模式允许您从集合中选择特定类型。它只匹配您要查找的类型,因此如果您的数组包含混合,则只能对特定类型进行操作。

例如:

let array: [Any] = [1, 1.2, "Hello", true, [1, 2, 3], "World!"]
for case let str as String in array {
    print(str)
}

输出:

Hello
World!

对于Swift 1.2:

在这种情况下,您正在投射view.subviews而不是button,因此您需要将其向下转换为所需类型的数组:

for button in view.subviews as! [AClass] {
    // do something with button
}

注意:如果底层数组类型不是[AClass],则会崩溃。这就是!上的as!告诉你的。如果您不确定类型,可以使用条件转换as?以及可选绑定if let

if let subviews = view.subviews as? [AClass] {
    // If we get here, then subviews is of type [AClass]
    for button in subviews {
        // do something with button
    }
}

对于Swift 1.1及更早版本:

for button in view.subviews as [AClass] {
    // do something with button
}

注意:如果子视图不是全部类型AClass,这也会崩溃。上面列出的安全方法也适用于早期版本的Swift。


118
投票

此选项更安全:

for case let button as AClass in view.subviews {
}

或者很敏捷的方式:

view.subviews
  .compactMap { $0 as AClass }
  .forEach { .... }

4
投票

您也可以使用where子句

for button in view.subviews where button is UIButton {
    ...
}

2
投票

vacawama提供的答案在Swift 1.0中是正确的。并且不再适用于Swift 2.0。

如果您尝试,您将收到类似于以下内容的错误:

'[AnyObject]'不能转换为'[A Class]';

在Swift 2.0中,您需要编写如下:

for button in view.subviews as! [AClass]
{
}

0
投票

提供的答案是正确的,我只是想添加它作为补充。

当使用强制转换的for循环时,代码将崩溃(正如其他人已经提到的)。

for button in view.subviews as! [AClass] {
    // do something with button
}

但不是使用if子句,

if let subviews = view.subviews as? [AClass] {
    // If we get here, then subviews is of type [AClass]
    ...
}

另一种方法是使用while循环:

/* If you need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let (index, subview) = iterator.next() as? (Int, AClass) {
    // Use the subview
    // ...
}

/* If you don't need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let subview = iterator.next().element as? AClass {
    // Use the subview
    // ...
}

如果数组的某些元素(但不是全部)可能是AClass类型,那么这似乎更方便。

虽然目前(从Swift 5开始),我会选择for-case循环:

for case let (index, subview as AClass) in view.subviews.enumerated() {
    // ...
}

for case let subview as AClass in view.subviews {
    // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.