When to use enumerateObjectsUsingBlock vs. for When to use enumerateObjectsUsingBlock vs. for multithreading multithreading

When to use enumerateObjectsUsingBlock vs. for


Ultimately, use whichever pattern you want to use and comes more naturally in the context.

While for(... in ...) is quite convenient and syntactically brief, enumerateObjectsUsingBlock: has a number of features that may or may not prove interesting:

  • enumerateObjectsUsingBlock: will be as fast or faster than fast enumeration (for(... in ...) uses the NSFastEnumeration support to implement enumeration). Fast enumeration requires translation from an internal representation to the representation for fast enumeration. There is overhead therein. Block-based enumeration allows the collection class to enumerate contents as quickly as the fastest traversal of the native storage format. Likely irrelevant for arrays, but it can be a huge difference for dictionaries.

  • "Don't use enumerateObjectsUsingBlock when you need to modify local variables" - not true; you can declare your locals as __block and they'll be writable in the block.

  • enumerateObjectsWithOptions:usingBlock: supports either concurrent or reverse enumeration.

  • with dictionaries, block based enumeration is the only way to retrieve the key and value simultaneously.

Personally, I use enumerateObjectsUsingBlock: more often than for (... in ...), but - again - personal choice.


For simple enumeration, simply using fast enumeration (i.e. a for…in… loop) is the more idiomatic option. The block method might be marginally faster, but that doesn't matter much in most cases — few programs are CPU-bound, and even then it's rare that the loop itself rather than the computation inside will be a bottleneck.

A simple loop also reads more clearly. Here's the boilerplate of the two versions:

for (id x in y){}[y enumerateObjectsUsingBlock:^(id x, NSUInteger index, BOOL *stop){}];

Even if you add a variable to track the index, the simple loop is easier to read.

So when you should use enumerateObjectsUsingBlock:? When you're storing a block to execute later or in multiple places. It's good for when you're actually using a block as a first-class function rather than an overwrought replacement for a loop body.


Although this question is old, things have not changed, the accepted answer is incorrect.

The enumerateObjectsUsingBlock API was not meant to supersede for-in, but for a totally different use case:

  • It allows the application of arbitrary, non-local logic. i.e. you don’t need to know what the block does to use it on an array.
  • Concurrent enumeration for large collections or heavy computation (using the withOptions: parameter)

Fast Enumeration with for-in is still the idiomatic method of enumerating a collection.

Fast Enumeration benefits from brevity of code, readability and additional optimizations which make it unnaturally fast. Faster than a old C for-loop!

A quick test concludes that in the year 2014 on iOS 7, enumerateObjectsUsingBlock is consistently 700% slower than for-in (based on 1mm iterations of a 100 item array).

Is performance a real practical concern here?

Definitely not, with rare exception.

The point is to demonstrate that there is little benefit to using enumerateObjectsUsingBlock: over for-in without a really good reason. It doesn't make the code more readable... or faster... or thread-safe. (another common misconception).

The choice comes down to personal preference. For me, the idiomatic and readable option wins. In this case, that is Fast Enumeration using for-in.

Benchmark:

NSMutableArray *arr = [NSMutableArray array];for (int i = 0; i < 100; i++) {    arr[i] = [NSString stringWithFormat:@"%d", i];}int i;__block NSUInteger length;i = 1000 * 1000;uint64_t a1 = mach_absolute_time();while (--i > 0) {    for (NSString *s in arr) {        length = s.length;    }}NSLog(@"For-in %llu", mach_absolute_time()-a1);i = 1000 * 1000;uint64_t b1 = mach_absolute_time();while (--i > 0) {    [arr enumerateObjectsUsingBlock:^(NSString *s, NSUInteger idx, BOOL *stop) {        length = s.length;    }];}NSLog(@"Enum %llu", mach_absolute_time()-b1);

Results:

2014-06-11 14:37:47.717 Test[57483:60b] For-in 10877540622014-06-11 14:37:55.492 Test[57483:60b] Enum   7775447746