Objective c "for each" (fast enumeration) -- evaluation of collection?

Marc Rochkind picture Marc Rochkind · Oct 7, 2010 · Viewed 15.2k times · Source

It seems from experimentation that the collection expression is evaluated only once. Consider this example:

static NSArray *a;

- (NSArray *)fcn
{
    if (a == nil)
        a = [NSArray arrayWithObjects:@"one", @"two", @"three", nil];
    NSLog(@"called");
    return a;
}

...

for (NSString *s in [self fcn])
    NSLog(@"%@", s);

The output is:

2010-10-07 07:37:31.419 WidePhotoViewer Lite[23694:207] called
2010-10-07 07:37:31.420 WidePhotoViewer Lite[23694:207] one
2010-10-07 07:37:31.425 WidePhotoViewer Lite[23694:207] two
2010-10-07 07:37:31.425 WidePhotoViewer Lite[23694:207] three

indicating that [self fcn] is called only once.

Can anyone confirm that this is the specified (as opposed to merely observed) behavior?

What I have in mind is doing something like this:

for (UIView *v in [innerView subviews]) {

instead of this:

NSArray *vs = [innerView subviews];
for (UIView *v in vs) {

Thoughts?

Answer

Shmurk picture Shmurk · Oct 7, 2010

This kind of for loop is called a "fast enumeration" (look at the NSFastEnumeration object). Apple's documentation says that in "for obj in expression", expression yields an object that conforms to the NSFastEnumeration protocol, so I guess that's the correct behaviour: the function is called once, an iterator is created once and used in the loop.