释放对象后分配'nil'的需要是啥
Posted
技术标签:
【中文标题】释放对象后分配\'nil\'的需要是啥【英文标题】:What is the need of assigning 'nil' after releasing an object释放对象后分配'nil'的需要是什么 【发布时间】:2012-02-14 11:35:30 【问题描述】:我通常在使用后释放对象
[myObject release];
但我在一些在线教程中发现他们在释放对象后分配了 nil。喜欢
[myObject release];
myObject = nil;
需要吗?
【问题讨论】:
Why set object to nil after sending release message in Obj-C的可能重复 其他候选人:Set pointers to nil after releaseIs it necessary to set pointers to nil after releaseWhen to set object references to nilDifference between release and release, then set to nil 【参考方案1】:关于是否有必要在发布后将指针设置为nil
是一个长期争论,但我认为这是一个好主意。
对象被释放后,你指向它的指针仍然指向同一个地方。如果您的版本已将保留计数设为 0,则该对象将被释放。如果您随后尝试向已释放的对象发送消息,您将收到 EXC_BAD_ACCESS 错误。但是,在指针设置为 nil
后向指针发送消息不会出错 - 它不会做任何事情。
论点的另一面是,如果您正在向一个已释放的对象发送消息,最好了解它并修复您的代码以确保它不会发生。
两个阵营都有聪明人。
【讨论】:
【参考方案2】:不,这不是严格要求的。
如果您的代码结构良好,则无需强制 myObject
等于 nil。
但这可能是一个好习惯:release
不会立即销毁对象,只是减少 retain
计数。因此,即使您调用 release,对象仍会存在一段时间,如果您尝试向其发送消息,则会产生问题。
使用myObject = nil;
可消除此问题,因为即使您向myObject
发送消息,实际上也不会发生任何事情。
【讨论】:
我只能添加这个great blog post by Jeff Lamarche。读起来很有趣。 如果在发布时保留计数将变为零,则该对象将被销毁。但是内存没有被清除,所以它可能看起来仍然存在。只有指针值设置为零。保护措施是,如果代码的另一部分通过指针引用并且指针为零,则不会发生任何不良情况,请注意,这涵盖了代码中的错误!。还有一种可能,赋值(id)0x42,这样如果有通过指针的acede错误会立即crash,然后代码就可以修复了。【参考方案3】:这不是必需的,但主要是样式问题。在发布后分配nil
可确保您不会意外再次使用已发布的引用(这可能会也可能不会导致崩溃)。简单地在引用上调用release
可能会使底层内存消失。但是,指针仍将指向(现在可能无效)地址,并且使用该指针的后续方法调用的结果是未定义的。
【讨论】:
【参考方案4】:不,这不是必需的。
这是一件安全的事情。如果你有
[myObject release];
然后你在其他地方做
[myObject doSomething];
那么你就会遇到问题。
如果你有
[myObject release];
myObject = nil;
然后你在其他地方做
[myObject doSomething];
然后什么都不会发生,因为你调用的是一个 nil 对象。因此,您的应用程序不会只是堆成一大堆。或者,如果您在代码中还有其他地方
[myObject release];
然后它将在一个 nil 对象上释放,因此不会过度释放。
显然你应该避免调用你已经释放的对象!
【讨论】:
【参考方案5】:我总是设置为零。
Apple 自己有时(记录在案)会检查 nil。
示例;
如果您设置了navigationItem.titleView
,如果您想恢复使用navigationItem.title
,则需要将其设置回nil
,否则您的标题将不会显示。
Apple 文档中有很多关于这种“零检查”的引用。
参考;
https://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationItem_Class/Reference/UINavigationItem.html
Restoring navigationItem.title after removing navigationItem.titleView
【讨论】:
【参考方案6】:不是真的,但最好用它来防止错误......
如果您在代码 myObject 发布时在某处调用它,它会给您一个严重错误, 但如果它被设置为 nil,则错误可能会被绕过
如果你尝试:
myObject.someProperty = 1;
或
if (myObject) ...
而您刚刚发布了 myObject,它可能会使您的应用崩溃...
【讨论】:
【参考方案7】:这不是必需的,但它通常被认为在所有环境中都是好的做法,但在-dealloc
方法中通常认为它是不必要的。
释放后将对象指针设置为 nil 的常见原因是,Objective-C 方法调度程序不会尝试向 nil 对象发送消息,这意味着您以后不小心使用该对象是安全的.
【讨论】:
【参考方案8】:在释放一个 abject 但不分配 NULL 后,它保留地址但内容被释放。所以现在它没有指向任何有效的内存位置。因此 ptr 现在是悬空指针,它可能有一个地址但没有指向任何有效的内存位置。 因此最好在释放分配的内存后分配 NULL,如下所示
ptr=NULL;
这样就解决了悬空问题。
【讨论】:
【参考方案9】:我建议采用混合方法。让我们看看典型的应用需求:
-
我们希望最大限度地减少生产中的应用程序崩溃
我们希望在测试时发现访问可能释放的内存等问题
一个好的解决方案是有条件地分配给:
-
发布版本中为零
调试中故意错误的指针(例如 0x20)。
这为生产构建带来了稳定性,但在调试模式下,任何访问变量的尝试都会显式地使应用程序崩溃。请注意,在对象上调用 release 并不能保证对象内存将被删除,因此需要显式设置为坏指针。
#ifdef DEBUG
#define RELEASE(obj) [(obj) release]; (obj) = (id)0x20;
#else
#define RELEASE(obj) [(obj) release]; (obj) = nil;
#endif
【讨论】:
【参考方案10】:在几年前我参加的一次 Apple 技术讲座中,Apple 工程师讨论了一些必须分配给 nil 的实例,但除了讨论的实例中的 dealloc 内部之外,我不记得其他细节.只要说你永远不必这样做是不正确的,或者这样做是不好的做法就足够了。有时你必须这样做。但大多数时候你不必这样做。抱歉我的记忆不太清楚。
【讨论】:
以上是关于释放对象后分配'nil'的需要是啥的主要内容,如果未能解决你的问题,请参考以下文章