在发布属性方面,我在iOS中看到了几种不同的内存管理方法。经过与同事的一些辩论后,利弊在我脑海中变得混乱。
我希望得到一个优点和缺点的摘要,这将允许我和其他人轻松选择默认方法,同时仍然了解何时进行例外处理。以下是我见过的3种变体:
假设@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 dealloc];
}
如果您要添加不同的变体,请在此处发表评论,然后我会修改操作。
答案 0 :(得分:2)
版本(1):是最好的。其他每个人都有可能有害的属性。
版本(2):通常建议不要在dealloc(或init)中使用访问器。这背后的原因是对象正在被拆除(或创建)并处于不一致状态。如果您正在编写一个库,其他人可能会稍后覆盖访问者,而不知道在对象处于不一致状态时可能会调用它。 (当然,即使Apple有时会违反此规则-[UIView initWithFrame:]
调用-[UIView setFrame:]
,如果参数不是CGRectZero
,这可以使调试变得有趣。
版本(3);将ivar设置为nil
没有任何用处,实际上它可能会掩盖错误并使调试更多变得困难。要了解为什么这是真的,请考虑以下代码段,假设myObject具有版本(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];
有趣的是,这段代码提供了一个机会来证明在nil
确实有意义之后将变量设置为release
时。通过如下修改代码可以使代码更具弹性。
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];
只需我0.02美元。