Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSMutableArray -init vs. +arrayWithCapacity:

I have two functions which one should i use? Please explain the difference.

A:

- (NSMutableArray *)FunctionA:(int)count {

    NSMutableArray *a = [[NSMutableArray alloc] init];

 for (int i = 0; i < count; i++) {
  [a addObject:[NSNumber numberWithInt:0] ];
    }

    return [a autorelease];
}

B:

-(NSMutableArray *)FunctionB:(int)count {

 NSMutableArray *b = [NSMutableArray arrayWithCapacity:count];

 for (int i=0;i<count; i++){  
  [b addObject:[NSNumber numberWithInt:0] ];  
 }

 return b;  //  or [b autorelease] ?
}
like image 849
aon Avatar asked Nov 13 '09 17:11

aon


3 Answers

The first creates a mutable array without specifying a capacity. This causes the array to have to grow when you add items. Internally, this is probably heavily optimized to occur "chunks at a time" but it's still necessary to grow the array and allocate more space when adding items.

The second gives the array a hint (you're probably going to need "this much" room) to avoid the overhead of growing the array when adding a known number of objects. Of course it will still grow larger if needed (as if you hadn't specified a capacity). You should use this approach if you already know the count ahead of time. It's faster with a large count.

This has a downside if you haven't measured before optimizing, however: If you're creating a mutable array with a very high capacity but not always using that capacity, you incur the penalty of allocating all that space for nothing.

Also, you don't autorelease B (as you commented out) because you didn't create the mutable array with init - you used a convenience method which did it itself, which means you're not responsible for releasing it. As I mentioned in a comment to another answer to your question, you can also create the array with:

[[NSMutableArray alloc] initWithCapacity:capacity];

... then release it when ready. This gives you greater control over memory usage than using the autorelease pool, which is an important consideration on the iPhone platform.

Remember, though: measure first, then optimize if necessary.

like image 118
Joshua Nozzi Avatar answered Nov 08 '22 21:11

Joshua Nozzi


Mutable objects still need to allocate space so that will allocate a default amount for say 10 objects. If you add an 11th, the mutable array will have to allocate new memory, copy the items over to the new memory, and free the old memory.

This is normally so fast you won't even notice but it could slow it down. Creating the mutable array with a size creates the array of the specified size initially so hopefully less resizing will occur.

like image 1
ACBurk Avatar answered Nov 08 '22 22:11

ACBurk


In the first example, you must manage the memory of the array, since you create it using +alloc and -init (which is why you need to send -autorelease to it).

In the second example, you do not have to manage the memory of the array, since it is returned to you autoreleased (because you created it using a convenience method). Also since you specify the desired size of the array up front, it is likely to be more efficient.

If you want to return an autoreleased array, then the second option would probably be more preferable, since +arrayWithCapacity: will return an already autoreleased array. Also since the array returned to you is already autoreleased, you do not have to send -autorelease to it yourself.

If you have any more concerns with memory management, then reading the Apple Memory Management Guidelines is a must.

like image 1
Alex Rozanski Avatar answered Nov 08 '22 23:11

Alex Rozanski