I'm looking for the standard idiom to iterate over an NSArray. My code needs to be suitable for OS X 10.4+.
相关问题
- CALayer - backgroundColor flipped?
- Core Data lightweight migration crashes after App
- back button text does not change
- iOS (objective-c) compression_decode_buffer() retu
- how to find the index position of the ARRAY Where
相关文章
- 现在使用swift开发ios应用好还是swift?
- TCC __TCCAccessRequest_block_invoke
- xcode 4 garbage collection removed?
- Unable to process app at this time due to a genera
- How can I add media attachments to my push notific
- didBeginContact:(SKPhysicsContact *)contact not in
- Custom Marker performance iOS, crash with result “
- Converting (u)int64_t to NSNumbers
Do this :-
For OS X 10.4.x and previous:
For OS X 10.5.x (or iPhone) and beyond:
Here is how you declare an array of strings and iterate over them:
The results of the test and source code are below (you can set the number of iterations in the app). The time is in milliseconds, and each entry is an average result of running the test 5-10 times. I found that generally it is accurate to 2-3 significant digits and after that it would vary with each run. That gives a margin of error of less than 1%. The test was running on an iPhone 3G as that's the target platform I was interested in.
The classes provided by Cocoa for handling data sets (NSDictionary, NSArray, NSSet etc.) provide a very nice interface for managing information, without having to worry about the bureaucracy of memory management, reallocation etc. Of course this does come at a cost though. I think it's pretty obvious that say using an NSArray of NSNumbers is going to be slower than a C Array of floats for simple iterations, so I decided to do some tests, and the results were pretty shocking! I wasn't expecting it to be this bad. Note: these tests are conducted on an iPhone 3G as that's the target platform I was interested in.
In this test I do a very simple random access performance comparison between a C float* and NSArray of NSNumbers
I create a simple loop to sum up the contents of each array and time them using mach_absolute_time(). The NSMutableArray takes on average 400 times longer!! (not 400 percent, just 400 times longer! thats 40,000% longer!).
Header:
// Array_Speed_TestViewController.h
// Array Speed Test
// Created by Mehmet Akten on 05/02/2009.
// Copyright MSA Visuals Ltd. 2009. All rights reserved.
Implementation:
// Array_Speed_TestViewController.m
// Array Speed Test
// Created by Mehmet Akten on 05/02/2009.
// Copyright MSA Visuals Ltd. 2009. All rights reserved.
From : memo.tv
////////////////////
Available since the introduction of blocks, this allows to iterate an array with blocks. Its syntax isn't as nice as fast enumeration, but there is one very interesting feature: concurrent enumeration. If enumeration order is not important and the jobs can be done in parallel without locking, this can provide a considerable speedup on a multi-core system. More about that in the concurrent enumeration section.
/////////// NSFastEnumerator
The idea behind fast enumeration is to use fast C array access to optimize iteration. Not only is it supposed to be faster than traditional NSEnumerator, but Objective-C 2.0 also provides a very concise syntax.
/////////////////
NSEnumerator
This is a form of external iteration: [myArray objectEnumerator] returns an object. This object has a method nextObject that we can call in a loop until it returns nil
/////////////////
objectAtIndex: enumeration
Using a for loop which increases an integer and querying the object using [myArray objectAtIndex:index] is the most basic form of enumeration.
////////////// From : darkdust.net
The generally-preferred code for 10.5+/iOS.
This construct is used to enumerate objects in a collection which conforms to the
NSFastEnumeration
protocol. 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 much faster than calling-objectAtIndex:
each time through the loop.It's also worth noting that while you technically can use a for-in loop to step through an
NSEnumerator
, I have found that this nullifies virtually all of the speed advantage of fast enumeration. The reason is that the defaultNSEnumerator
implementation of-countByEnumeratingWithState:objects:count:
places only one object in the buffer on each call.I reported this in
radar://6296108
(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.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:
You can also use
-enumerateObjectsWithOptions:usingBlock:
and passNSEnumerationConcurrent
and/orNSEnumerationReverse
as the options argument.10.4 or earlier
The standard idiom for pre-10.5 is to use an
NSEnumerator
and a while loop, like so:I recommend keeping it simple. Tying yourself to an array type is inflexible, and the purported speed increase of using
-objectAtIndex:
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.When using
-objectEnumerator
, you very easily change to another enumerable collection (like anNSSet
, keys in anNSDictionary
, etc.), or even switch to-reverseObjectEnumerator
to enumerate an array backwards, all with no other code changes. If the iteration code is in a method, you could even pass in anyNSEnumerator
and the code doesn't even have to care about what it's iterating. Further, anNSEnumerator
(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.Perhaps the biggest thing an
NSEnumerator
(or fast enumeration) protects you from is having a mutable collection (array or otherwise) change underneath you without your knowledge 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! :-)Add
each
method in yourNSArray category
, you gonna need it a lotCode taken from ObjectiveSugar