Objective-C enumerateObjectsUsingBlock vs fast enumeration?
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 ;)
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"