views:

189

answers:

2

Everything i've read about objective-c memory management makes it sound incredible easy. To paraphrase everyone: "release whatever you alloc, retain or copy". But I think there are some more specific cases that are not so clear cut. Below are some sample situations. What is the correct procedure for each:

SITUATION #1:

Foo *foo = [[foo alloc] init];
Foo *fooToo = [[[foo alloc] init] autorelease];

foo = fooToo;

does foo need to be released before it is assigned to fooToo?

SITUATION #2 I seem to get a lot of crashes when I do things like: (.h and .m mashed together for convenience)

Foo *foo;
@property (nonatomic, retain) Foo *foo;
@synthesize foo;

-(id)init{
self = [super init];
}

-(void)dealloc{
[super dealloc];
[foo release];
}

I'm constantly told "always release in dealloc what you set a retain property for". But this will crash, if done like I've shown.

SITUATION #3 A similar situation that will also crash: (.h and .m mashed together for convenience)

Foo *foo;
@property (nonatomic, retain) Foo *foo;
@synthesize foo;

-(id)init{
self = [super init];
self.foo = nil;
}

-(void)dealloc{
[super dealloc];
[foo release];
}

for some reason when my code makes it down to dealloc, foo isn't == nil.

SITUATION #4 Finally, just a question, what general thought process do people use when deciding between

 self.foo = bar;

and

 foo = bar;

when foo is declared the same as in the above cases? Is self.foo just another way of coding:

foo = [bar retain];

+6  A: 

Situation #1:

Yes, you do need to release foo before you lose your reference to it. Given that you allocated it, you are responsible for releasing it. If you re-assign foo before releasing it, you cannot release it anymore!

Situation #2:

The proper implementation of dealloc is:

- (void)dealloc {
    [foo release];
    [super dealloc];
}

The dealloc method needs to call the super's dealloc method not the release method. Also, you need release the fields first before calling [super dealloc]

Situation #3: Same as situation #2.

Situation #4:

I always prefer using self.foo = bar, as it does the following steps automatically, if needed:

  1. releasing foo
  2. retaining bar
  3. assigning foo to bar

The assignments foo = bar and foo = [bar retain] don't release the previous object of foo.

notnoop
Interesting! Good information for someone who is just getting started in Objective-C. (me)
Jeff Meatball Yang
`self.foo = bar` is exactly equivalent to sending `[self setFoo:bar]` (unless a different setter has been chosen).
Chuck
self.foo = bar will also send KVO notifications. foo = bar will not.
nall
+4  A: 

Wait. Stop. Msaeed's answer is correct, line-by-line, but fails to emphasize the real problem.

You are either failing to think like a computer or you are assuming way too much magic per line of code.

Please don't take it as an insult -- it is a very easy mistake to make and one that just about every programmer makes when new to an environment (I made some truly fantastic magical assumptions when starting with Objective-C in 1989).

Let's reconsider the situations.

SITUATION #1: ... delete irrelevant code ...

foo = fooToo;

This is a simple assignment. Whatever foo contained before this -- a reference to an object in your case -- will now be overwritten by the value of fooToo. There is no magic. There is no additional method execution or lines of code involved.

If foo contained a reference to a retained object pior to that line of code. The reference will be overwritten. If you need to release foo before overwriting the reference, do so, but that is orthogonal to the assignment.

SITUATION #2: ... delete irrelevant code ...

-(void)dealloc{ [super dealloc]; [foo release]; }

Play computer; you are asking super to dealloc and then assuming an instance variable is valid after super has been deallocated. Bad news. Boom.

There is no magic here. foo is a reference through self to the instance variable. The -dealloc destroys self and, thus, foo is no longer valid.

(I believe the static analyzer will catch this. If not, it should.)

SITUATION #3:

See #2. This is the exact same problem. You are accessing an instance variable of an instance that is no longer valid.

SITUATION #4:

self.foo = bar;

Is the exact same thing as:

`[self setFoo: bar];

(Barring any setter= shenanigans)

Thus, the key difference is whatever the implementation -- hand written or @synthesized -- of -setFoo: does. In your case, it retains bar. Which is different than foo = bar; in that no retain happens; it is just an assignment of the reference to bar.

I would highly recommend that you revisit the Objective-C introduction documentation. It'll help. However, I would also encourage you to step back and really think through exactly what each line of code in the above situations are doing. There is no magic and the actual behavior is very straightforward.

bbum