Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The generally-preferred code for 10.5+/iOS.</p> <pre><code>for (id object in array) { // do something with object } </code></pre> <p>This construct is used to enumerate objects in a collection which conforms to the <code>[NSFastEnumeration protocol]</code>(<a href="http://developer.apple.com/documentation/Cocoa/Reference/NSFastEnumeration_protocol/" rel="noreferrer">Cocoa Reference</a>). This approach has a speed advantage because it stores pointers to several objects (obtained via a single method call) in a buffer and iterates through them by advancing through the buffer using pointer arithmetic. This is <em>much</em> faster than calling <code>-objectAtIndex:</code> each time through the loop.</p> <p>It's also worth noting that while you technically <em>can</em> use a for-in loop to step through an <code>NSEnumerator</code>, I have found that this nullifies virtually all of the speed advantage of fast enumeration. The reason is that the default <code>NSEnumerator</code> implementation of <code>-countByEnumeratingWithState:objects:count:</code> places only one object in the buffer on each call.</p> <p>I reported this in <code>radar://6296108</code> (Fast enumeration of NSEnumerators is sluggish) but it was returned as Not To Be Fixed. The reason is that fast enumeration pre-fetches a group of objects, and if you want to enumerate only to a given point in the enumerator (e.g. until a particular object is found, or condition is met) and use the same enumerator after breaking out of the loop, it would often be the case that several objects would be skipped.</p> <p>If you are coding for OS X 10.6 / iOS 4.0 and above, you also have the option of using block-based APIs to enumerate arrays and other collections:</p> <pre><code>[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) { // do something with object }]; </code></pre> <p>You can also use <code>-enumerateObjectsWithOptions:usingBlock:</code> and pass <code>NSEnumerationConcurrent</code> and/or <code>NSEnumerationReverse</code> as the options argument.</p> <hr> <h3>10.4 or earlier</h3> <p>The standard idiom for pre-10.5 is to use an <code>NSEnumerator</code> and a while loop, like so:</p> <pre><code>NSEnumerator *e = [array objectEnumerator]; id object; while (object = [e nextObject]) { // do something with object } </code></pre> <p>I recommend keeping it simple. Tying yourself to an array type is inflexible, and the purported speed increase of using <code>-objectAtIndex:</code> is insignificant to the improvement with fast enumeration on 10.5+ anyway. (Fast enumeration actually uses pointer arithmetic on the underlying data structure, and removes most of the method call overhead.) Premature optimization is never a good idea — it results in messier code to solve a problem that isn't your bottleneck anyway.</p> <p>When using <strong><code>-objectEnumerator</code></strong>, you very easily change to another enumerable collection (like an <code>NSSet</code>, keys in an <code>NSDictionary</code>, etc.), or even switch to <strong><code>-reverseObjectEnumerator</code></strong> to enumerate an array backwards, all with no other code changes. If the iteration code is in a method, you could even pass in any <code>NSEnumerator</code> and the code doesn't even have to care about <em>what</em> it's iterating. Further, an <code>NSEnumerator</code> (at least those provided by Apple code) retains the collection it's enumerating as long as there are more objects, so you don't have to worry about how long an autoreleased object will exist.</p> <p>Perhaps the biggest thing an <code>NSEnumerator</code> (or fast enumeration) protects you from is having a mutable collection (array or otherwise) change underneath you <em>without your knowledge</em> while you're enumerating it. If you access the objects by index, you can run into strange exceptions or off-by-one errors (often long after the problem has occurred) that can be horrific to debug. Enumeration using one of the standard idioms has a "fail-fast" behavior, so the problem (caused by incorrect code) will manifest itself immediately when you try to access the next object after the mutation has occurred. As programs get more complex and multi-threaded, or even depend on something that third-party code may modify, fragile enumeration code becomes increasingly problematic. Encapsulation and abstraction FTW! :-)</p> <hr>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload