I have been looking through the questions asked on StackOverflow, but there are so many about memory management in Objective-C that I couldn't find the answer I was looking for.
The question is if it is ok (and recommnded) to call autorelease before adding a newly created object to a collection (like NSMutableArray)? Or should I release it explicitly after adding it. (I know NSMutableArray willl retain the object)
This illustrates my question:
Scenario A (autorelease):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
}
Scenario B (explicit release):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
[obj release];
}
I assume both are correct, but I am not sure, and I sure don't know what the preffered way is.
Can the Objective-C gurus shed some light on this?
IMHO, which way is 'right' is a matter of preference. I don't disagree with the responders who advocate not using
autorelease
, but my preference is to useautorelease
unless there is an overwhelmingly compelling reason not to. I'll list my reasons and you can decide whether or not their appropriate to your style of programming.As Chuck pointed out, there is a semi-urban legend that there's some kind of overhead to using autorelease pools. This could not be further from the truth, and this comes from countless hours spent using Shark.app to squeeze the last bit of performance out of code. Trying to optimize for this is deep in to "premature optimization" territory. If, and only if, Shark.app gives you hard data that this might be a problem should you even consider looking in to it.
As others pointed out, an autoreleased object is "released at some later point". This means they linger around, taking up memory, until that "later point" rolls around. For "most" cases, this is at the bottom of an event processing pass before the run loop sleeps until the next event (timer, user clicking something, etc).
Occasionally, though, you will need to get rid of those temporary objects sooner, rather than later. For example, you need to process a huge, multi-megabyte file, or tens of thousands of rows from a database. When this happens, you'll need to place a
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
at a well chosen point, followed by a[pool release];
at the bottom. This almost always happens in some kind of "loop batch processing", so it's usually at the start and bottom of some critical loop. Again, this should be evidence based, not hunch based. Instrument.app's ObjectAlloc is what you use to find these trouble spots.The main reason why I prefer
autorelease
torelease
, though, is that it is much easier to write leak-free programs. In short, if you choose to go therelease
route, you need to guarantee thatrelease
is eventually sent toobj
, under all circumstances. While this seems like it might be simple, it is actually surprisingly hard to do in practice. Take your example, for instance:Now imagine that for some reason, something, somewhere, subtly violates your assumption that
array
is mutable, maybe as the result of using some method to process the results, and the returned array containing the processed results was created as aNSArray
. When you sendaddObject:
to that immutableNSArray
, an exception will be thrown, and you will never sendobj
itsrelease
message. Or maybe something goes wrong somewhere between whenobj
wasalloc
d and the required call torelease
, like you check some condition andreturn()
immediately by mistake because it slipped your mind that that call torelease
later on must take place.You have just leaked an object. And probably signed yourself up to several days of trying to find out where and why it is your leaking it. From experience, you will spend many hours looking at that code above, convinced that it could not possibly be the source of the leak because you very clearly send
obj
arelease
. Then, after several days, you will experience what can only be described as a religious epiphany as you are enlightened to the cause of the problem.Consider the
autorelease
case:Now, it no longer matters what happens because it's virtually impossible to leak
obj
accidentally, even under extremely unusual or exceptional corner cases.