更新请看底部。
当使用(保留)合成属性时,最好的dealloc方法是将属性设置为nil。之所以说这是“最好”的方法,是因为它确保了属性声明所暗示的所有协议都得到满足。例如,如果您的属性被声明为原子性(除非您显式地声明为非原子性),仅通过在dealloc中使用属性将其设置为nil,才能保证取消设置该属性时具有相同的原子性保证。这也意味着它会正确地处理对象的任何键值观察 - 这可能特别重要,特别是如果您使用Cocoa绑定。
对于没有相应属性的(可能是私有的)实例变量进行自己的内存管理时,有几种惯用法。最简单但最危险的方法是简单地释放iVar,如下所示:
- (void)dealloc
{
[myArray release];
[super dealloc];
}
这将导致iVar上的保留被释放,但正如其他人所提到的,现在可能过时的指针仍然存在,可能会被过时或未保留的指向正在被dealloc的对象的指针访问。接下来沿途的是另一个答案建议的习语:
- (void)dealloc
{
[myArray release], myArray = nil;
[super dealloc];
}
如果更加谨慎,可以使用以下习语:
- (void)dealloc
{
id temp = myArray;
myArray = nil;
[temp release];
[super dealloc];
}
这进一步限制了通过在释放指向的对象之前清除iVar来防止指针过时读取的机会。但是,由于指令重新排序的潜力,即使如此,在所有架构上也不能完全保证不会出现过时读取。
尽管并发和内存管理还有很多要说的,但通常情况下,如果您有一个@synthesized属性setter,则应在dealloc中使用它。这样做意味着,如果更改@property的行为,则dealloc行为将自动与@property声明正确匹配。
重要提示:使用原子属性!=线程安全。(实际上,如果问我,原子属性是浪费,但是…)有关详细信息,请参见
here。
更新
最近又被投票了,虽然我仍然坚持我在这里关于合成保留属性的原子保证所说的话,而且原始答案中的其他内容本身就具有价值,但我觉得有必要讲述另一面的故事。戴夫·德隆在评论中暗示了其中的一些内容,但我认为将详细信息添加到主要答案中是值得的。
我认为保持原子性保证的唯一方法是通过设置属性的setter将其设置为
nil
。
但是你不应该在意,原因如下:如果一个对象正在被
dealloc
,那么(如果您的对象图正确)就不应该有任何对该对象的活动引用。 如果没有对该对象的活动引用,则不可能有任何人关心清除属性的操作的原子性保证。
我在原始答案中还提到了KVO作为在
dealloc
中使用setter的原因,但Dave DeLong在评论中提到了KVO作为反驳的理由。 他是对的,原因如下:同样,如果一个对象正在
dealloc
,则所有KVO观察者应该已从其中删除(再次,不应该有任何活动引用,无论是KVO还是其他)。 实际上,如果不是这种情况,很快就会看到控制台消息,告诉您对象仍然处于观察状态。
简而言之,在
dealloc
中无法使原子性保证等同于合成的setter,但它永远不会有影响(如果有影响,那么其他问题就出现了)。