More Specific, General Objective-C Memory Management
Everything i've read about objective-c memory management makes it sound incredible easy. To 开发者_Go百科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]
;
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:
- releasing
foo
- retaining
bar
- assigning
foo
tobar
The assignments foo = bar
and foo = [bar retain]
don't release the previous object of foo
.
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 retain
s 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.
精彩评论