4

我知道在 Objective-c 中有一种非常简单的方法可以像这样声明变量:

NSArray* myArray;

@property(retain) NSArray* myArray;

@synthesize myArray;

这样,您可以在保留变量的同时将 self.myArray 用作 setter 和 getter。然而,这也将允许您做一件事,那就是避免自己使用 dealloc。据我了解,这两行是相同的:

self.myArray = nil;
[myArray release];

我的问题是,哪一种是首选方式?在任何情况下,其中一个会起作用而另一个不起作用?

编辑:对不起,我的意思是释放,而不是释放......

4

4 回答 4

4

你永远不应该自己调用 dealloc(除非在非常非正统的情况下)。

而不是 dealloc,您应该调用[myArray release]并让释放的进程为您处理这个问题。

这里查看更多信息,而不是您可能想要的 dealloc 方法。

于 2010-12-31T23:01:48.823 回答
3

底部更新。

使用(保留)合成属性时,执行 dealloc 职责的最佳方法是将属性设置为 nil。我之所以说这是“最好”的方式,是因为它可以确保满足财产声明所暗示的所有合同。例如,如果您的属性被声明为原子的(除非您特别声明它是非原子的),那么保证在 dealloc 上取消设置此属性的唯一方法是使用相同的原子保证将其设置为 nil 使用dealloc 中的属性。这也意味着它对于对象的任何 Key-Value Observations 都会正确运行 - 这可能很重要,特别是如果您使用 Cocoa Bindings。

在为没有相应属性的(可能是私有的)实例变量进行自己的内存管理时,有几个习惯用法。最简单但最危险的方法是简单地释放 iVar,如下所示:

- (void)dealloc
{
    [myArray release];

    [super dealloc];
}

这将导致 iVar 上的保留被释放,但正如其他人所提到的,将留下现在可能陈旧的指针,如果错误,可能会被陈旧或非保留的指针访问,这些指针可能存在指向正在被访问的对象解除分配。接下来是另一个答案建议的成语:

- (void)dealloc
{
    [myArray release], myArray = nil;

    [super dealloc];
}

一个更安全、更迂腐的习语是:

- (void)dealloc
{
    id temp = myArray;
    myArray = nil;
    [temp release];

    [super dealloc];
}

这通过在释放指向的对象之前清除 iVar 进一步限制了指针过时读取的机会。但是,由于指令重新排序的可能性,即使这也不能 100% 保证在所有架构上都不会出现过时的读取。

尽管关于并发和内存管理的话题还有很多话要说,但总的来说,如果你有一个 @synthesized 属性设置器,你应该只在 dealloc 中使用它。这样做意味着如果您更改 @property 的行为,则对于 @property 声明,dealloc 行为将自动正确。

重要提示:使用原子属性!= 线程安全。(事实上​​,如果你问我原子属性是一种浪费,但是......)更多细节请看这里

更新

这最近再次得到了投票,虽然我支持我在这里所说的关于具有综合保留属性的原子保证,并且原始答案中的一些其他内容本身就有价值,但我觉得有必要告诉另一方故事。Dave DeLong 在评论中提到了其中的一些内容,但我认为值得在主要答案中添加细节。

我认为保持原子性保证的唯一方法是nil通过 setter 将属性设置为。但是您不应该关心,原因如下:如果正在dealloc编辑对象,则意味着(如果您的对象图是正确的)不应该有对该对象的活动引用。如果没有对对象的活动引用,那么任何人都不可能关心清除属性的操作的原子性保证。

我还在原始答案中提到了 KVO 作为使用 setter in 的原因dealloc,但 Dave DeLong 在评论中提到了 KVO 作为对位。他是对的,原因如下:同样,如果一个对象正在被dealloc编辑,那么所有的 KVO 观察者都应该已经被移除了(同样,应该没有活的引用,不管 KVO 与否)。事实上,如果不是这种情况,不久之后您就会看到一条控制台消息,告诉您您的对象消失了,但观察结果仍然存在。

简而言之,虽然您不能使原子性保证等同于 in 中的合成 setter 的保证dealloc,但它永远不重要(如果确实如此,其他东西就会被破坏。)

于 2010-12-31T23:29:35.473 回答
1

每当您有任何作为对象的实例变量时,您都必须在 dealloc 方法中释放它。所以在你的情况下你必须使用

- (void)dealloc
{
    [myArray release], myArray = nil;

    [super dealloc];
}
于 2010-12-31T22:34:25.737 回答
1

理论上设置为 nil 应该与释放 ivar 具有相同的效果。但是,您永远不应该直接调用 dealloc 方法。在 dealloc 方法中,你有时会看到 David 提到的成语,具体来说:

[myArray release], myArray = nil;

这样做的原因是为了避免极不可能的竞争条件,即有人可能会在 dealloc 完成之前尝试访问已释放的对象。通过将属性分配给 nil 这允许尝试的访问优雅地失败。

于 2010-12-31T23:10:38.583 回答