views:

694

answers:

4

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] ?
}
+6  A: 

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.

Joshua Nozzi
+1  A: 

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.

ACBurk
+1  A: 

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.

Perspx
A: 

I'd use B:

The pluses I see with it are

  • The array will not need to resize as it grows larger
  • arrayWithCapacity: autoreleases for you so you don't have to, this improves code readability imho

I hope that helps.

Bryan McLemore
Though in situations where you might want more control (over how much memory you're using), you can still create it with [[NSMutableArray alloc] initWithCapacity:c], then release it when you're ready.
Joshua Nozzi
Just to clarify my previous comment - this is an important consideration on the iPhone, which I mention because of the "iphone" tag. :-)
Joshua Nozzi
Absolutely true. I didn't notice the tag, and that may be a serious consideration assuming this is a large array. However, the memory management guidelines are there for a reason. Consistent usage is very important, and should only be broken if you absolutely know why and there's not a cleaner way.
Bryan McLemore
I'm not sure I understand why that's a "however". :-D Whether or not you use an autorelease pool or hint an array's capacity doesn't imply or necessitate breaking memory management rules. Could you clarify what you meant?
Joshua Nozzi
While I'd definitely bow to your experience, I was referring more to breaking them by creating an object and then returning it without it being autoreleased. If you acquired it from the function and then forgot to release it at all, a reasonably common mistake, you'd have a potentially serious leak. Indeed, having a function like a who didn't autorelease at the end would result in a clang warning for potential memory leaks. Sorry for not responding earlier was at lunch.
Bryan McLemore