Search code examples
swiftfor-loopfor-in-loop

For-in loop goes one-too-far and finds 'nil' while unwrapping


It looks like the following Swift for-in loop is trying to go through more elements than are in the array.

For instance, this code:

var list:[Int?] = [1,2,3,4,5,6,7]

print("C-Style for loop")
for var i=0; i<list.count; i++ 
{
    var x:Int = list[i]!
    print(x)
}

print("\nFor-in loop")
for var x:Int! in list
{
    print(x)
}

Gets this output:

C-Style for loop
1
2
3
4
5
6
7

For each loop
1
2
3
4
5
6
7
fatal error: unexpectedly found nil while unwrapping an Optional value
... 
Illegal instruction: 4

I must be missing something here. Shouldn't list.count be the number of elements that the for-in loop tries to unwrap?

Not pictured above, the for-in loop works as expected if use an [Int] list instead of [Int?] with no unwrapping.

I am on Swift version 2.1.1.


Solution

  • Basically you've done something you're not supposed to do, and thus you've stumbled on something that's probably a compiler bug (because the compiler didn't stop you). Very nice!

    Now the solution. You are evidently trying to unwrap with your Int!. To unwrap safely, use for case syntax:

    let list:[Int?] = [1,2,3,4,5,6,7]
    for case let x? in list
    {
        print(x) // 1, 2, 3, 4, 5, 6, 7
    }
    

    Another way (same result):

    let list:[Int?] = [1,2,3,4,5,6,7]
    list.flatMap{$0}.forEach{print($0)} // 1, 2, 3, 4, 5, 6, 7