I've seen several different approaches to memory management in iOS as regards releasing properties. After some debate with colleagues, the pros and cons have become muddled in my head.
I'm hoping to get a summary of pros and cons that will allow myself and others to easily choose a default approach while still understanding when to make exceptions. Here are the 3 variations I've seen:
Assume @property (nonatomic, retain) MyObject *foo;
// Release-only. Seems to be the favored approach in Apple's sample code.
- (void)dealloc {
[foo release];
[super dealloc];
}
// Property accessor set to nil.
- (void)dealloc {
self.foo = nil;
[super dealloc];
}
// Release, then nil.
- (void)dealloc {
[foo release];
foo = nil;
[super deall开发者_如何学运维oc];
}
If you have a different variation to add, comment here and I'll edit the op.
Versions (1): is the best. Each of the others have attributes that may be harmful.
Version (2): It is generally advised not to use accessors in dealloc (or init). The reasoning behind this is that the object is in the process of being torn-down (or created) and is in an inconsistent state. This is especially true if you are writing a library where someone else may later override an accessor unaware that it may be called when the object is in an inconsistent state. (Of course even Apple sometimes breaks this rule -[UIView initWithFrame:]
calls -[UIView setFrame:]
if the argument is not CGRectZero
which can make for fun debugging.
Version (3); Setting the ivar to nil
serves no useful purpose, indeed it may mask an error and make debugging more difficult. To see why this is true, consider the following piece of code, assume myObject has a version (3) dealloc
.
FastMovingTrain* train = [[FastMoving alloc] init];
MyObject* myObject = [[MyObject alloc] init];
myObject.foo = train;
[train release];
// my myObject.foo is the only thing retaining train
...
....
[myObject release];
// Because of version (3) dealloc if myObject
// points to the dealloced memory this line
// will silently fail...
[myObject.foo applyBrakes];
Interestingly enough this code provides an opportunity to demonstrate when setting a variable to nil
after a release
does make sense. The code can be made more resilient by modifying it as follows.
FastMovingTrain* train = [[FastMoving alloc] init];
MyObject* myObject = [[MyObject alloc] init];
myObject.foo = train;
[train release];
// my myObject.foo is the only thing retaining train
...
....
[myObject release];
myObject = nil;
// This assertion will fail.
NSAssert(myObject, @"myObject must not be nil");
[myObject.foo applyBrakes];
Just my $0.02.
精彩评论