在viewDidUnload中设置为nil,但在dealloc中释放

时间:2011-04-20 22:19:05

标签: iphone objective-c cocoa-touch memory-management

我一整天都在阅读有关为什么在viewDidUnload中将视图设置为nil并在dealloc中发布的原因。所有文章都在重复同样的事情。是的,我知道幕后指示是不同的,但实际的区别是什么?

var = nil

  1. 如果var是保留的属性,则回收旧对象var指向的内存。
  2. 将var设置为nil。
  3. [var release]

    1. 回收内存变量点。
    2. var现在指向任何东西,相当于nil
    3. 对我来说,回收内存的两种方式都有相同的最终结果。那么为什么一个在另一个呢?每本书都告诉我在viewDidUnload中设置为nil并在dealloc中发布。如果视图在viewDidUnload中发布并在dealloc中填充,则应该指出可能发生的不良事件。

      ·H

      #import <UIKit/UIKit.h>
      @interface DisclosureDetailController : UIViewController {
       UILabel* label;
      }
      @property (nonatomic, retain) IBOutlet UILabel* label;
      @end
      

      的.m

      #import "DisclosureDetailController.h"
      @implementation DisclosureDetailController
      @synthesize label;
      - (void)viewDidUnload {
       self.label = nil;
       // OR [self.label release];
       [super viewDidUnload];
      }
      - (void)dealloc {
       [self.label release];
       // OR self.label = nil;
      }
      

2 个答案:

答案 0 :(得分:25)

首先,行

[self.label release];
无论你在哪里打电话,

都是绝对错误的。您应该从不调用-release关于属性访问的结果。这与编写[[self label] release]完全相同,我希望你能认识到这是错误的。

您的代码示例应如下所示:

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

如果我们先看-viewDidUnload,那就很简单了。 self.label = nil;是正确的。同样正确的是[self setLabel:nil];。虽然不太好,但写[label release], label = nil;也是可以接受的。最后一种形式不是很好,因为它绕过了setter方法,这可能比简单地释放属性做更多的事情(例如,它可能保持关注属性值的内部状态)。它还绕过了KVO通知。

这里真正的问题是你在-dealloc中做了什么。很多人都认为说self.label = nil;是完全没问题的,实际上,大多数时候这都会有效。问题是,其余的时间会导致细微的错误。调用setter有两件事可以做。首先,如果手动实现setter方法,它可能会导致类中的副作用(即使您没有自己实现setter,也可能是子类)。第二是它可以播放KVO通知。当你在-dealloc时,这两件事都不合适。通过直接释放ivar,如[label release];,您可以避免潜在的副作用和KVO通知。

答案 1 :(得分:4)

实际差异如下。

使用属性访问器将属性设置为nil将使合成方法在释放现有属性后保留新的nil属性。

// we will take for granted that you synthesize this property
@property (nonatomic, retain) IBOutlet UILabel* label;

我们将使用属性访问器并将其设置为nil。

//This will in actuality set the new value of nil to the label variable after
//releasing the existing label that it had a retain count on.
self.label = nil; 

接下来我们将直接发布

//This line on the other hand will merely release the label directly. 
//As soon as the label is deallocated you will have a handle to an invalid object. 
//(memory space that used to be your label)
[label release];

现在我们将展示属性访问器的简化版本。 (不要用字面意思)

//Simply put the following is an pseudo equivalent of the property setter.
[label release]
label = nil;

这里的要点是属性访问器处理释放它保留的标签。并将其设置为您提供的任何东西(在这种情况下为零)

因此添加以下代码

label = nil;

不释放保留的对象会导致内存泄漏,并且您将在不再有指针的标签上有保留计数。

注意

  

另一件需要考虑的事情。   任何指针都是零。将能够   接受消息。作为回报他们   将以零回复。一个对象   另一方面被释放了   一旦该内存被释放   你的信息很有可能发生   抛出一个错误。结果是   不可预知的。这是一个很好的理由   用于将属性设置为nil。   它不仅会处理发布   对于它持有的对象。但   它也会给你一个对象   可以安全地发送消息而不吹   起来。

好点@WaltSellers

访问变量 - 无论是属性访问者还是实例变量。 - 完全释放后。将导致“未定义”操作。这意味着访问可能会正常运行,或者它可能会破坏应用程序的其他部分,或者它可能会快速爆炸并终止违规应用程序。基本上在释放后将变量设置为nil将使您能够超越该错误。

与我分开的提示

克服属性访问器和实例变量的误解我只是@synthesize并告诉它设置一个变量名。

@synthesize label = _label;

这样做可以让我将self.label与其实例变量区分开来。如果没有前面的_

,你就不能直接访问label变量了