Saturday, April 20, 2013

Unexpected side effect of fast enumeration in Objective-C

Fast enumeration is a relatively new capability in Objective-C. For a thorough survey of all the ways one can enumerate through a collection, you can see this post.

In a recent project I had a code sequence like this (modified here for illustration):


        NSArray *array = @[@1, @2];
        NSNumber *number = nil;

        for (number in array) {
            NSLog(@"number: %@", number);
        }
        
        NSLog(@"Last number: %@", number);


My expectation was that at the end of the for loop the number variable would hold the last value of the array. Here's what I get instead:


2013-04-19 17:13:06.223 FastEnumBug[49016:303] number: 1
2013-04-19 17:13:06.240 FastEnumBug[49016:303] number: 2
2013-04-19 17:13:06.241 FastEnumBug[49016:303] Last number: (null)


Strangely the value comes back as nil. Which is what it was initialized to before entering the loop. Could that be the case ? Let's try this instead:

        NSArray *array = @[@1, @2];
        NSNumber *number = @100;

        for (number in array) {
            NSLog(@"number: %@", number);
        }
        
        NSLog(@"Last number: %@", number);

which produces:


2013-04-20 18:47:34.209 FastEnumBug[62468:303] number: 1
2013-04-20 18:47:34.212 FastEnumBug[62468:303] number: 2
2013-04-20 18:47:34.212 FastEnumBug[62468:303] Last number: (null)


Nope, I still get nil, not the @100 value at the entry of the loop. So it seems that fast enumeration blocks  reset the value of the iteration pointer in the outer context back to nil. This is, at least to me, unexpected. Maybe it's a bug. I'll see what Apple has to say.

No comments: