Type casting in for-in loop Type casting in for-in loop swift swift

Type casting in for-in loop


For Swift 2 and later:

Swift 2 adds case patterns to for loops, which makes it even easier and safer to type cast in a for loop:

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

Why is this better than what you could do in Swift 1.2 and earlier? Because case patterns allow you to pick your specific type out of the collection. It only matches the type you are looking for, so if your array contains a mixture, you can operate on only a specific type.

For example:

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

Output:

HelloWorld!

For Swift 1.2:

In this case, you are casting view.subviews and not button, so you need to downcast it to the array of the type you want:

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

Note: If the underlying array type is not [AClass], this will crash. That is what the ! on as! is telling you. If you're not sure about the type you can use a conditional cast as? along with optional binding 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    }}

For Swift 1.1 and earlier:

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

Note: This also will crash if the subviews aren't all of type AClass. The safe method listed above also works with earlier versions of Swift.


This option is more secure:

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

or swifty way:

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


The answers provided are correct, I just wanted to add this as an addition.

When using a for loop with force casting, the code will crash (as already mentioned by others).

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

But instead of using an if-clause,

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

another way is to use a while-loop:

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

Which seems to be more convenient if some elements (but not all) of the array might be of type AClass.

Although for now (as of Swift 5), I'd go for the for-case loop:

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