I’m fairly new to iPhone development and I’ve hit a roadblock in my understanding of memory management. I’ve read through the Memory Management Guide for Cocoa and have read many, many questions and answers on SO, but have not found a complete answer.
If I have an instance method that creates an object, every example I’ve seen seems to use an autorelease call:
-(NSArray *)findThings {
NSArray* things = [[[NSArray alloc] init] autorelease];
// add some lovely things to my shiny new array
return things;
}
Forgetting the contrived example, everything I’ve read about iPhone dev best practices says that autorelease pools are discouraged, but how can I implement the above example without one? If this method is called many, many times, it feels like I run the risk of clogging the iPhone’s autorelease pool with, well, “things”, which seems to go against the need to keep resource use to a minimum on such a constrained platform.
I considered the following:
-(NSArray *)findThings {
NSArray* things = [[NSArray alloc] init];
// add some lovely things to my shiny new array
[things release];
return things;
}
But then ‘things’ would have a retain count of zero before it passes to the calling method, so I feel like there’s a significant risk of the object being deallocated between the call to [things release] and the method which calls findThings actually using the result.
I was a bit confused by the rule from the Memory Management Guide which states:
A received object is normally
guaranteed to remain valid within the
method it was received in. (…) That method
may also safely return the object to
its invoker.
I wasn’t sure whether this meant as the writer of an instance method I could safely perform the release without the risk of the object being deallocated until the calling method’s scope ended, or whether as a user of classes in the frameworks provided by apple I could assume that I didn’t have to worry about retain/release/etc for objects I received from those classes as long as the method didn’t have new/init/alloc/copy/whatever in its name.
So to summarise,
- Can I use release before returning an object instead of autorelease to avoid using an autorelease pool on the iPhone?
- If not, is there a better pattern for this that doesn’t involve the autorelease pool?
- Am I missing something fundamental here? It seems like there’s a hole in the docs.
Thanks in advance
Yes, you’re right autorelease pools are discouraged for iPhone development when they’re not absolutely necessary. They are discouraged because it allows objects to stay in memory longer then necessary this is a problem when developing applications for the iPhone, where memory is scarce. Autoreleased objects don’t get released until it makes it back to the main autorelease pool created in main.c and this could be a long time. (unless you created your own autorelease pool, I’ll talk about this last.)
A case where an autoreleased object is not necessary:
The first case is more convenient since I don’t have to worry about releasing
stringlater but it could have been easily been replaced with:For these cases avoiding the autoreleased object is recommended.
When you’re passing back objects using autorelease is unavoidable.
You must use:
Since the object is invalid as soon as you call
release.In cases where you’re using a large amount of autoreleased memory you should create and drain your own autorelease pool so the autorelease memory doesn’t stay around longer then necessary.
[pool drain] also releases the pool, see the NSAutoreleasePool Reference for more information.