iOS中的Dealloc方法并将对象设置为nil

时间:2011-07-21 15:39:58

标签: objective-c ios memory-management dealloc

我有一个非常基本的问题。在我看到的一些例子中,对象只是在dealloc方法中释放。在其他情况下,对象将被释放,然后设置为nil。是否有一个原因?释放后有没有设定为零?

4 个答案:

答案 0 :(得分:23)

dealloc的三种方法

<强> 1。刚发布

- (void)dealloc {
    [airplane release];
    [super dealloc];
}

现在,对象引用指向一个随机位置,可能是以下两种情况之一:

  1. 很可能是垃圾,因为内存位置不能被解释为对象。
  2. 很少会有一个不同的对象,因为内存已经被重用来创建一个新对象。
  3. 通过这个指针调用另一个方法的效果是这三个中的一个(其中一个是未定义的):

    • EXC_BAD_ACCESS崩溃,因为指针指向垃圾。
    • 未定义选择器崩溃,因为它指向没有该方法的有效对象。
    • 成功执行方法,因为新对象具有相同名称的方法。

    <强> 2。发布并且没有

    - (void)dealloc {
        [airplane release], airplane = nil;
        [super dealloc];
    }
    

    现在对象引用为nil,并且忽略任何进一步的方法调用。这可能会在您的代码中默默地导致定义但无法预料的横向效果,但至少它不会使您的应用程序崩溃。

    第3。无和发布

    - (void)dealloc {
        id temp = airplane;
        airplane = nil;
        [temp release];
        [super dealloc];
    }
    

    这和以前一样,但它删除了release和nil之间的小窗口,其中对象引用指向无效对象。

    哪一个最好?

    这是一个选择问题:

    • 如果你喜欢崩溃,请选择发布。
    • 如果您宁愿忽略错误,请选择nil + release或release + nil。
    • 如果您正在使用NSZombieEnabled=TRUE,那么只需释放,不要让僵尸无效!

    宏和僵尸

    推迟选择的一种简单方法是使用宏。而是[airplane release]您编写safeRelease(x),其中safeRelease是您添加到.pch目标文件的以下宏:

    #ifdef DEBUG
      #define safeRelease(x) [x release]
    #else
      #define safeRelease(x) [x release], x=nil
    #endif
    

    这个宏不尊重僵尸。问题在于:当NSZombieEnabledTRUE时,对象变为NSZombie。如果您的对象引用为零,则发送给他的任何调用都将被忽略。

    为了解决这个问题,这里有一个来自Kevin Ballard的宏,只有在NSZombieEnabledFALSE时才会将指针设置为无效的编组引用。如果没有启用僵尸,这可以保证在调试期间崩溃,但不会留下僵尸。

    #if DEBUG
      #define safeRelease(x) do { [x release]; if (!getenv("NSZombieEnabled")) x = (id)0xDEADBEEF; } while (0)
    #else
      #define safeRelease(x) [x release], x = nil
    #endif
    

    参考

    Apple没有关于哪一个最好的建议。如果你想阅读社区的想法,这里有一些链接(评论主题也很棒):

答案 1 :(得分:3)

此代码段涵盖了所有基础已准备好剪切并粘贴.pch文件中。

// SAFE_RELEASE
//      Releases an object, then does other things based on context.
//
//      The intention is to fail early during internal testing but prevent
//          customers from experiencing crashes if at all possible.
//
// For more information see:
//      http://stackoverflow.com/questions/6778793/dealloc-method-in-ios-and-setting-objects-to-nil
//
// Debug build:
//      If zombies are enabled, the macro just calls |release|. The zombie
//          mechanism will continue to be used to find messages sent to
//          the deallocated object.
//      Otherwise, zombies are not enabled, so the macro sets the object to a
//          invalid memory address. (0xDEADBEEF.) This will intentionally
//          cause a crash if the object is used, allowing the bug to be found
//          and fixed immediately.
//
// Release build:
//      The macro calls |release| normally. Then it sets the object to nil to
//          prevent a possible crash caused by sending a message to a
//          deallocated object. Messages sent to nil are always allowed.
//
#if DEBUG
#define SAFE_RELEASE(x) \
    do { \
        [x release]; \
        if (!getenv("NSZombieEnabled")) \
            x = (id)0xDEADBEEF; \
    } while (0)
#else
#define SAFE_RELEASE(x) \
    [x release], x = nil
#endif

该代码在功能上等同于Jano的第二版safeRelease,但添加了Google's coding standards的文档和合规性。

答案 2 :(得分:1)

如果在多个地方进行了dealloc调用,则将对象变量设置为nil可确保它不会被错误地多次释放。如果具有dealloc的函数从多个位置调用,或者可以由外部代码(即其他类)任意调用,则逻辑相同。

在现实生活中,这通常发生在封闭对象“可重用”时 - 支持多轮内容初始化/拆卸。对象指针的nil - 然后成为对象状态的一个有价值的组件 - 它意味着对象现在是“空的”。

对于一般情况感到抱歉。

答案 3 :(得分:0)

- (void)dealloc
{
     [searchPlace release];
     [super dealloc];
}
- (void)viewDidUnload
{
     [super viewDidUnload];
     self.searchPlace = nil;
}

这就像你说的那样吗?