Objective-c中释放变量的正确方法

发布于 2024-10-09 14:10:22 字数 391 浏览 1 评论 0原文

我知道在 Objective-c 中有一种非常简单的方法来声明变量,如下所示:

NSArray* myArray;

@property(retain) NSArray* myArray;

@synthesize myArray;

这样您可以使用 self.myArray 作为 setter 和 getter,同时保留变量。然而,这还允许您做另一件事,即避免使用 dealloc。据我了解,这两行是相同的:

self.myArray = nil;
[myArray release];

我的问题是,哪一种是首选方式?是否存在其中一种有效而另一种无效的情况?

编辑:抱歉,我的意思是释放,而不是解除分配......

I know that in Objective-c there's a very easy way to declare variables like this:

NSArray* myArray;

@property(retain) NSArray* myArray;

@synthesize myArray;

This way you can use self.myArray as both the setter and getter while retaining the variable. However this will also allow you to do one more thing, which is avoiding yourself using dealloc. As far as I understand, this two lines are the same:

self.myArray = nil;
[myArray release];

My question is, which one is the preferred way? Is there any cases where one of them will work and the other one won't?

EDIT: Sorry, I meant release, not dealloc...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

会傲 2024-10-16 14:10:22

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

您应该调用 [myArray release] 并让已发布的进程为您处理此问题,而不是 dealloc。

请查看此处,获取比您想象的更多的信息就像 dealloc 方法一样。

You should never call dealloc yourself (except under very unorthodox circumstances).

Instead of dealloc, you should call [myArray release] and let the released process take care of this for you.

Have a look here for way more info than you'd probably like on a dealloc method as well.

女皇必胜 2024-10-16 14:10:22

更新在底部。

当使用(保留)合成属性时,执行释放任务的最佳方法是将属性设置为零。我之所以说这是“最好”的方式,是因为它确保了财产声明所隐含的所有契约都得到满足。例如,如果你的属性被声明为原子的(它将会是原子的,除非你明确声明它是非原子的),保证在 dealloc 上取消设置该属性的唯一方法是使用相同的原子保证将其设置为 nil dealloc 中的属性。这也意味着它对于对象的任何键值观察都会正确运行 - 这可能很重要,特别是如果您使用 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 的行为,则 dealloc 行为将自动正确于 @property 声明。

重要提示:使用原子属性!=线程安全。 (事实上​​,如果你问我原子属性是一种浪费,但是......)请参阅此处了解更多详细信息。

更新

最近再次获得投票,虽然我坚持我在这里所说的关于具有合成保留属性的原子保证,并且原始答案中的其他一些内容本身就有价值,但我觉得需要讲述故事的另一面。戴夫·德隆在评论中提到了其中的一些内容,但我认为值得在主要答案中添加细节。

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

我还在原始答案中提到了 KVO 作为在dealloc 中使用 setter 的原因,但 Dave DeLong 在评论中提到了 KVO 作为对比。他是对的,原因如下:同样,如果一个对象正在被dealloced,那么所有 KVO 观察者都应该已经从中删除(同样,无论是否有 KVO,都不应该有活动引用)。事实上,如果情况并非如此,不久您就会看到一条控制台消息,告诉您您的对象消失了,而观察结果仍然存在。

简而言之,虽然您无法使原子性保证与dealloc中的合成setter等效,但它应该无关紧要(如果确实如此,其他东西就会被破坏。)

Updates at bottom.

When working with (retain) synthesized properties, the best way to do your dealloc duties is to set the property to nil. The reason I say that this is the "best" way is that it ensures that all the contracts implied by the property declaration are met. For instance, if your property was declared atomic (which it will be, unless you specifically declare it nonatomic) the ONLY way to guarantee that the unsetting of this property on dealloc is done with the same atomic guarantees is to set it to nil using the property in dealloc. It also means that it will behave correctly with regard to any Key-Value Observations of your object - This can be important especially if you use Cocoa Bindings.

When doing your own memory management for a (perhaps private) instance variable without a corresponding property, there are several idioms. The simplest, but most dangerous, is to simply release the iVar, like so:

- (void)dealloc
{
    [myArray release];

    [super dealloc];
}

This will cause the retain on the iVar to be released, but as others mentioned, will leave the now-potentially-stale pointer around to potentially, if erroneously, be accessed by stale or non-retained pointers that may exist pointing to the object being dealloced. Next along the way is the idiom suggested by another answer:

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

    [super dealloc];
}

An even safer, if more pedantic, idiom for this is:

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

    [super dealloc];
}

This further limits the chances for a stale read of the pointer by clearing the iVar BEFORE releasing the object pointed to. But, due to the potential for instruction reordering, even this is not a 100% guarantee against a stale read on all architectures.

Although there's much more to say on the topic of concurrency and memory management, in general, if you have a @synthesized property setter, you should just use it in dealloc. Doing so means that if you change the behavior of the @property the dealloc behavior will automatically be correct with respect to the @property declaration.

IMPORTANT NOTE: Using atomic properties != thread safety. (In fact, if you ask me atomic properties are a waste, but...) See here for more details.

UPDATE

This recently got upvoted again, and while I stand by what I said here about the atomic guarantees with synthesized retain properties, and some other content in the original answer is of value on its own, I feel the need to tell the other side of the story. Dave DeLong alluded to some of this in the comments, but I figured it'd be worth adding the detail to the main answer.

I maintain it's true that the only way to maintain the atomicity guarantees is to set the property to nil via the setter. BUT you shouldn't care, and here's why: If an object is being dealloced, that means (if your object graph is correct) that there should be no living references to that object. If there are no living references to the object, then it's not possible for anyone to be caring about the atomicity guarantees of the operation that clears the property.

I also mentioned KVO in the original answer as a reason to use the setter in dealloc, but Dave DeLong mentioned KVO in the comments as a counterpoint. He's right, and here's why: Again, if an object is being dealloced, all KVO observers should already have been removed from it (again, there should be no living references, KVO or not). Indeed, if this is not the case it won't be long until you'd see a console message telling you that your object went away with observations still in place.

In short, while you can't make atomicity guarantees equivalent to those of a synthesized setter in dealloc, it should never matter (and if it does, something else is broken.)

你另情深 2024-10-16 14:10:22

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

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

    [super dealloc];
}

Whenever you have any instance variable that is an object, you have to release it in the dealloc method. So in your case you have to use

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

    [super dealloc];
}
随心而道 2024-10-16 14:10:22

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

[myArray release], myArray = nil;

这样做的原因是为了避免极不可能发生的竞争情况,即有人可能会在 dealloc 完成之前尝试访问已释放的对象。通过将该属性分配为 nil,这允许尝试访问正常失败。

Setting to nil in theory should have the same effect as releasing the ivar. You should never call the dealloc method directly however. In the dealloc method you sometimes see the idiom mentioned by David, specifically:

[myArray release], myArray = nil;

The reason for this is to avoid a very unlikely race condition where someone might try accessing the released object before dealloc completes. By assigning the property to nil this allows the attempted access to fail gracefully.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文