在for-in循环中进行类型转换


116

我有这个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]
vacawama 2014年

2
哈哈,我没想到这一点,当然,将数组转换为AClass数组更好,谢谢大家。您可以对此做出回答,所以我可以给您代表:)
Arbitur 2014年

Answers:


173

对于Swift 2和更高版本:

Swift 2 在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],则将崩溃。那就是!on 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>
Arbitur

因此,出于好奇,是否有办法在for循环内执行多个case语句?EG,如果我想对按钮做一件事,对文本字段做另一件事?
RonLugge

125

此选项更安全:

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

或迅速的方式:

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

1
这似乎是更好的答案,因为没有强制力。
帕特里克

1
这应该是公认的答案。是最好的和正确的之一!
托马斯·卡尔蒙

正确答案。简短而简单。
帕夏

4

您还可以使用where子句

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

12
where子句是一个布尔型保护,但不强制转换button循环体内的类型,这是其他解决方案的目标。因此,这只能在元素上运行的循环体view.subviews,其是UIButtonS,但不利于例如,在调用AClass的特异性方法button
约翰·惠特利

1
@JohnWhitley你是正确的,where只有警卫而没有演员。
edelaney05'2013-10-30

where对于仅需要布尔值守卫的情况(可能是双关语),可能会更优雅,更易读。
STO

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
    // ...
}

如果数组的某些元素(但不是全部)可能是type,这似乎更方便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 {
    // ...
}

这里只是一个疑问...在这里快速枚举的函数是否执行迭代/循环..只是认为重构会降低性能不会很大...谢谢
Amber K

2

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

如果尝试,将出现类似以下错误:

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

在Swift 2.0中,您需要这样写:

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

0

您可以与此同时执行强制转换并确保安全:

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

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.