PruitIgoe
PruitIgoe

Reputation: 6384

Objective-C: autorelease confusion

Say I have a class DoStuff, and that class has two methods, like so

- (NSMutableDictionary* returnToCaller) methodOne : (NSString* ) myString {

    NSMutableDictionary* bundleOfJoy = [[NSMutableDictionary alloc] init]; 

    if (myString) { 
       bundleOfJoy = [self methodTwo];
    }

    return bundleOfJoy; 

} 

- (NSMutableDictionary* returnToMethodOne) methodTwo {

    NSMutableDictionary* anotherDictionary = [[NSMutableDictionary alloc] init]; 
    [anotherDictionary setObject: @"hardcodedstring" forKey: @"theKey"];

    return anotherDictionary;  
}

ok, so bear with me as my memory-management-fu is kind of weak. I can't release the two dictionaries manually created after the returns as the release command won't be called. I can't do it before the returns or I pass no values. My understanding then is the way to handle this is with an autorelease pool...

pool = [[NSAutoreleasePool alloc] init];

and init my objects as such

NSMutableDictionary* anotherDictionary = [[[NSMutableDictionary alloc] init] autorelease];

and then call

[pool drain];

so, if that is correct, where do I init pool? In awakeFromNib? And where do I call [pool drain]?

if this is incorrect could someone straighten me out (but please type slowly) : D

thanks

Upvotes: 1

Views: 746

Answers (6)

Joe
Joe

Reputation: 57169

The autorelease pool will already be set up for you in most cases. Unless you are running code in a separate thread without using GCD you do not need to allocate and drain a pool. Even if you did put an autorelease pool in that method the object would be autoreleased too soon since you would have to drain within the same method. With that said to get an autoreleased object you can use either a convenience constructor or add autorelease to your alloc/init.

- (NSMutableDictionary* /*returnToMethodOne*/) methodTwo {
    //Convenience constructor
    NSMutableDictionary* anotherDictionary = [NSMutableDictionary dictionary];
    //or    
    //NSMutableDictionary* anotherDictionary = [[[NSMutableDictionary alloc] init] autorelease]; 
    [anotherDictionary setObject: @"hardcodedstring" forKey: @"theKey"];

    return anotherDictionary; 
}

Upvotes: 2

matt
matt

Reputation: 534893

The best solution is to use ARC. Then you'll never have to worry about this again. :)

Even then, you need to understand what ARC is doing for you. The discussion in my iOS programming book applies equally to Mac OS X:

http://www.apeth.com/iOSBook/ch12.html#_memory_management

Upvotes: 2

Tomasz Stanczak
Tomasz Stanczak

Reputation: 13164

And you typically wouldn't create and drain the pool yourself, it is being done by the framework for you, so you just autorelease objects you want to released later.

Of course this way you cannot control the time, so in case you create a lot of temporary autoreleased objects in some part of your program, you can wrap this piece of code in pool create and drain:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
... create objects...
[pool drain];

But as I said, it is just an option for special cases.

Upvotes: 2

FreeAsInBeer
FreeAsInBeer

Reputation: 12979

You need to autorelease the objects that you return. They will exist for your calling code to use but will be released at some arbitrary point later in time.

- (NSMutableDictionary* returnToMethodOne) methodTwo {
    NSMutableDictionary* anotherDictionary = [[NSMutableDictionary alloc] init]; 
    [anotherDictionary setObject: @"hardcodedstring" forKey: @"theKey"];

    return [anotherDictionary autorelease]; 
}

You should almost never need to use autorelease pools unless you're needing to ensure low memory usage while running loops that generate lots of objects.

Another way to achieve this functionality would be to create an autoreleased object for which you don't have to manage the memory (using a convenience constructor). For example:

- (NSMutableDictionary* returnToMethodOne) methodTwo {
    NSMutableDictionary* anotherDictionary = [NSMutableDictionary dictionary]; // Creates an autoreleased NSMutableDictionary object.
    [anotherDictionary setObject: @"hardcodedstring" forKey: @"theKey"];

    return anotherDictionary; // No `autorelease` call because it's not our memory to manage.
}

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

The system maintains an autorelease pool for you. It is created before your program is started, and drained regularly when the event loop gets control. In most situations, you do not need your own autorelease pool: just call autorelease before returning your object, and you will be OK.

P.S. If you would like to learn about situations when you do need your own autorelease pool, Apple put together a nice guide for you.

Upvotes: 2

Mathieu Hausherr
Mathieu Hausherr

Reputation: 3485

There is an automatic NSAutoreleasePool in each thread and you don't have to create one instead you're creating a new thread.

Use [pool release]; instead of [pool drain] unless to have a memory leak.

For your code it's the responsibility of the method to release allocated object so add

 return [bundleOfJoy autorelease]; 
 return [anotherDictionary autorelease];

Upvotes: 2

Related Questions