35

What are the advantages and disadvantages of the following two approaches:

enumerate using block

NSArray *myArray = [NSArray new];
[myArray enumerateObjectsUsingBlock:^(id anObject, NSUInteger idx, BOOL *stop) {
    if (anObject == someOtherObject) {
        [anObject doSomething:idx];
        *stop = YES;
    }
}];

fast enumeration

NSArray *myArray = [NSArray new];
int idx = 0
for (id anObject in myArray) {
    if (anObject == someOtherObject) {
        [anObject doSomething:idx];
        break;
    }
    ++idx;
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
lmirosevic
  • 15,787
  • 13
  • 70
  • 116
  • Possible duplicate of [When to use enumerateObjectsUsingBlock vs. for](http://stackoverflow.com/questions/4486622/when-to-use-enumerateobjectsusingblock-vs-for) – Cœur Nov 25 '15 at 11:51

2 Answers2

49

This blog post covers the major differences. In summary:

  • Fast enumeration is available on OS X 10.5+, blocks are available on 10.6+
  • For simple enumeration, fast enumeration is a bit faster than block-based enumeration
  • It's easier (and more performant) to do concurrent or reverse enumeration with block-based enumeration than with fast enumeration
  • When enumerating over an NSDictionary you can get key and value in one hit with a block-based enumerator, whereas with fast enumeration you have to use the key to retrieve the value in a separate message send.

Regarding the last point (NSDictionary enumeration), compare this:

for (id key in dictionary)
{
    id obj = [dictionary objectForKey: key];
    // do something with key and obj
}

to this:

[dictionary enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
    // do something with key and obj
}];

In addition, both methods protect mutable collections from mutation inside the enumeration loop. Interestingly, if you try to mutate the collection inside a block-based enumeration, you get an exception thrown by CoreFoundation's __NSFastEnumerationMutationHandler, suggesting that there's some common code under the hood.

 NSMutableArray *myArray = [NSMutableArray arrayWithObjects:@"a", @"b", nil];
 [myArray enumerateObjectsUsingBlock:^(id anObject, NSUInteger idx, BOOL *stop) {
     // Attempt to mutate the array during enumeration
     [myArray addObject:@"c"];
 }];

Output:

2011-12-14 22:37:53.716 Untitled[5809:707] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x109614190> was mutated while being enumerated.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff8cca7286 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff8319ad5e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8cd311dc __NSFastEnumerationMutationHandler + 172
    3   CoreFoundation                      0x00007fff8cc9efb4 __NSArrayEnumerate + 612
    4   Untitled                            0x00000001094efcea main + 250
    5   Untitled                            0x00000001094efbe4 start + 52
    6   ???                                 0x0000000000000001 0x0 + 1
)
terminate called throwing an exceptionRun Command: line 1:  5809 Abort trap: 6           ./"$2"
Simon Whitaker
  • 20,506
  • 4
  • 62
  • 79
4

First thoughts that come to my mind

  • Blocks are available in iOS 4 and later so if you need to support older versions then you can not use the block syntax.

  • They are pretty equivalent in terms of what they do apart from you can't accidentally mess up the counter in the block version.

  • One other potential difference is that you can define the block elsewhere and pass in different blocks dependant on your state.

Hopefully this was just a very rough example as the code snippet is pretty poor and there are more efficient way of doing this ;)

Paul.s
  • 38,494
  • 5
  • 70
  • 88
  • Also, if I recall correctly, it was stated in a WWDC 2010 video that block enumeration is even more performant than fast enumeration. – Mark Adams Dec 14 '11 at 18:33
  • 1
    That's the problem with the videos you know there is good stuff in there but good luck finding it again at a later date. I looked at the docs for [Enumeration: Traversing a Collection’s Elements](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Enumerators.html) and there was no stand out mention of a performance increase :S – Paul.s Dec 14 '11 at 18:38
  • 2
    Actually, I just found it. It's the "What's New in Foundation for iOS 4" video from 2010. – Mark Adams Dec 14 '11 at 18:58
  • Nice work it really is hard to track stuff down even if you know what video it is in. – Paul.s Dec 15 '11 at 09:03