【问题标题】:Type casting in for-in loop在 for-in 循环中进行类型转换
【发布时间】:2014-11-22 11:32:25
【问题描述】:

我有这个 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 button in view.subviews as [AClass]怎么样
  • 哈哈我没有想到,当然最好将数组转换为AClass数组,谢谢。您可以对此做出回答,以便我可以给您一些代表:)

标签: for-loop swift for-in-loop


【解决方案1】:

对于 Swift 2 及更高版本:

Swift 2 将 case 模式 添加到 for 循环中,这使得在 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。

【讨论】:

  • 只是给像我这样一开始没有得到它的其他人的注释 - 类名必须放在 [ ] 括号内,就像在这个例子中一样。也许只有我一个人,但起初我认为这只是代码示例中的一种格式选择:) 我认为这是因为我们正在转换为一个数组。
  • @kmcgrady 它只是[Class] 看起来比Array<Class> 好多了。
  • 那么出于好奇,有没有办法在 for 循环中执行多个 case 语句?例如,如果我想对按钮做一件事,对文本字段做另一件事?
【解决方案2】:

这个选项更安全:

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

或快速的方式:

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

【讨论】:

    【解决方案3】:

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

    使用强制转换的 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 {
        // ...
    }
    

    【讨论】:

    • 这里只是一个疑问......快速枚举函数是否在这里执行迭代/循环......只是认为重构会失去性能不会很好......谢谢
    【解决方案4】:

    您也可以使用where 子句

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

    【讨论】:

    • where 子句是一个布尔守卫,但不会在循环体内强制转换 button 的类型,这是其他解决方案的目标。所以这只会在view.subviews 的元素上运行循环体,这些元素是UIButtons,但没有帮助,例如在button 上调用AClass 特定的方法。
    • @JohnWhitley 你说得对,where 只守卫不施放。
    • where 对于只需要一个布尔值守卫的情况(双关语无意)可能更优雅和可读。
    【解决方案5】:

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

    如果你尝试,你会得到一个类似的错误:

    '[AnyObject]' 不能转换为'[AClass]';

    在 Swift 2.0 中你需要这样写:

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

    【讨论】:

      【解决方案6】:

      您可以同时执行投射并确保安全:

      for button in view.subviews.compactMap({ $0 as? AClass }) {
      
      }
      

      【讨论】:

        【解决方案7】:

        如果你想在你的循环中有一个索引

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-13
          • 1970-01-01
          • 2012-11-25
          • 1970-01-01
          • 1970-01-01
          • 2021-10-22
          • 2019-03-28
          • 1970-01-01
          相关资源
          最近更新 更多