views:

58

answers:

3

I am trying to understand a little more about memory management. Knowing that I need to release anything that I have init or alloc'ed I am confused about the following:

- (NSMutableArray *)getData {
    NSMutableArray *data = [[NSMutableArray alloc] init];
    NSString *first = @"First object";
    [data addObject:first];
    NSString *second = @"Second object";
    [data addObject:second];

    return data;

}

Since I used alloc and init, I know I need to release my data object. But if I add autorelease to the init part or to the return, it crashes when I run the method.

What is the correct way to do something like this with correct memory management for iPhone?

+1  A: 

You're on the right track. You should pair every alloc/init with either release or autorelease, which will cause the object to get cleaned up as soon as the final reference to it goes away.

The pattern is something like this:

- (SomeObject*)generateSomeObject
{
    SomeObject* someObject = [[[SomeObject alloc] init] autorelease];
    ...
    return someObject;
}
Shaggy Frog
I tried this, but it crashes when I add autorelease, with nothing in the debugger console.
Nic Hubbard
A: 

Are you assigning the result of this method to an instance variable? Keep in mind that things that added to the autorelease pool are released at some point in the future (usually at the end of the run loop), so if you assign it to an instance variable, and the end of the run loop comes around, your instance variable will end up pointing to garbage (or sometimes a different object) unless you retain it.

The name of the method (getData) would suggest that the object being returned should be autoreleased, so you can create the array with [NSMutableArray array], fill it up as per usual, and then return it from the method.

If the code that invokes getData wants the array to survive an iteration of the run loop, it needs to retain it, but also, it needs to make sure to release the array when it's finally finished with it — this is usually done in your dealloc method.

dreamlax
I am just using it to build an array from some objects so that I can keep all that code in another .m file. Then, in my apps viewDidLoad method I am calling that class method which returns the array, then I am assigning it to a pointer which is retained. Doing it wrong?
Nic Hubbard
@Nic: If you are retaining it, then you are doing it right. Are you sure that everything contained within the array is also correctly managed?
dreamlax
Check the post above to see what worked. I had to retain the caller.
Nic Hubbard
+2  A: 

You should autorelease, like you said. The caller probably needs to retain, like this - especially if storing into an instance variable:

NSMutableArray *array = [[obj getData] retain];

Later, when it's totally done with it:

[array release]; // balances the retain above
Graham Perks
This worked, thank you. But what I don't understand is I am putting that into a point which is retained. Why would I need to retain again?
Nic Hubbard
@Nic Hubbard: What is "a point which is retained"?
Chuck
I'm sorry, a pointer. So I used @property (nonatomic, retain) NSMutableArray *missions; in my .h file.
Nic Hubbard
if you have a @property with the retain flag, then you don't need to call retain as long as you are actually going through the mutator (since the mutator will call retain for you). In other words, do this: self.missions = [obj getData]; instead of: missions = [obj getData]. Adding the "self." calls the mutator. Without it, you are just assigning to an ivar and it won't matter what you put in your @property declaration.
Josh Hinman
Thanks for reminding me of this. It is working great.
Nic Hubbard