NSMutableArray initWithCapacity nuances

Matt Gallagher has written a pretty informative article on Cocoa's collection classes, along with a couple of benchmarks (with & without initWithCapacity:, as well as cross class comparisons)

http://cocoawithlove.com/2008/08/nsarray-or-nsset-nsdictionary-or.html

His test (source available) for an NSMutableArray of length 1,000,000 took 0.582256sec without capacity and just 0.572139sec with capacity.

Test                                       | Time
[NSMutableArray array]                     | 0.582256 seconds
[NSMutableArray arrayWithCapacity:1000000] | 0.572139 seconds
Iterating contents                         | 0.004713 seconds

I'd say that in 99% of the use cases [NSMutableArray array] is just fine. If you do know the actual size of the resulting array, however, it won't hurt to use [NSMutableArray arrayWithCapacity:] either.


And then there is this article by Peter Ammon (who is a developer on Apple’s AppKit/Foundation team) featuring several insightful benchmarks:

http://ridiculousfish.com/blog/archives/2005/12/23/array/


Edit (March 12th 2012):

More insight on array initialization performance from http://darkdust.net/writings/objective-c/nsarray-enumeration-performance

[…] I [=>DarkDust] also wanted to know whether the performance is any different depending on how the array was created. I tested two different methods:

  • Create a C array which references the object instances and create the array using initWithObjects:count:.
  • Create a NSMutableArray and subsequently add objects using addObject:.

[…] there is a difference when allocating: the initWithObjects:count: method is faster. With a very large number of objects, this difference can become significant.


Edit (March 6th 2014):

Further more insight on array initialization performance from http://ciechanowski.me/blog/2014/03/05/exposing-nsmutablearray/:

Let’s allocate new arrays with initial capacity set to consecutive powers of two:

for (int i = 0; i < 16; i++) {
    NSLog(@"%@", [[[NSMutableArray alloc] initWithCapacity:1 << i] explored_description]);
}

Surprise surprise:

size:  2 // requested capacity:   1
size:  2 // requested capacity:   2
size:  4 // requested capacity:   4
size:  8 // requested capacity:   8
size: 16 // requested capacity:  16
size: 16 // requested capacity:  32
size: 16 // requested capacity:  64
size: 16 // requested capacity: 128
...
// 'size: 16' all the way down

Whether any space is wasted by giving too big a capacity is actually an implementation detail that Apple deliberately doesn't expose, I guess. NSMutableArray is a class cluster which means you don't actually get an instance of NSMutableArray but some other, specialized class following the same interface. And Apple doesn't tell you which class gets returned in which case and how it's behaving. So it's hard to give real advices here.

If you really know that on average you'll need a capacity of X, just use it. Otherwise, unless you have performance problems I wouldn't care about the capacity at all and just use [NSMutableArray array]...