【问题标题】:iPhone dealloc and viewDidUnload IssueiPhone dealloc 和 viewDidUnload 问题
【发布时间】:2012-04-10 07:20:48
【问题描述】:

我有一个关于 dealloc() 和 viewDidUnload() 方法的快速问题。我注意到很多代码示例,人们似乎在做不同的事情。

另外,我可能会补充一点,ARC 不是一个选项。

(1) 我是否应该在 dealloc() 方法中将所有属性设置为 nil,包括 IBOutlets。例如,我是否应该释放实例变量 [_myArrary release] 并设置 self.myArrary = nil。

(2) 在 vi​​ewDidUnload 中,我认为我必须将所有 IBOutlets 设置为 nil,以及在 viewDidLoad 中创建的任何内容。但是,myString 呢,假设它在调用 viewDidLoad 后在另一个方法中初始化。我应该将它设置为 nil 吗?

如果我有一些这样声明的属性:

@property (nonatomic, retain) IBOutlet UITableViewCell *myTableCell;
@property (nonatomic, retain) IBOutlet UILabel *myLabel;
@property (nonatomic, retain) NSArray *myArrary;
@property (nonatomic, retain) NSString *myString;

I synthesize them as such:

@synthesize myArrary = _myArrary;
@synthesize myTableCell;
@synthesize myLabel;
@synthesize myString;

- (void)viewDidLoad
{
    [super viewDidLoad];

    _myArrary = [NSArrary alloc] initWithObjects:@"testObject", nil];
}

- (void)viewDidUnload
{
    self.myArrary = nil;

    self.myTableCell = nil;

    self.myLabel = nil;

    [super viewDidUnload];
}

- (void)dealloc
{   
    [_myArray release];

    [super dealloc];
}

【问题讨论】:

    标签: iphone objective-c ios


    【解决方案1】:
    1. 在 dealloc 中将属性/变量设置为 nil 无关紧要,因为一旦对象被释放,您将无法访问它们。使用保留属性,做

      self.varname = nil;

      将释放变量并将其设置为 nil。很多人更喜欢只发布它们,我更喜欢将保留属性设置为 nil 以保持一致性。

    2. 在 viewDidUnload 中,您应该释放并设置为 nil 任何不需要的内容,并且在视图再次加载时将重新创建。这不是一个严格的规则,而是保持尽可能多的可用内存的良好做法。如果您的字符串将在 viewDidLoad 中重新创建,并且在再次加载视图之前您不需要访问它,那么您可能应该释放它(为了安全起见,我会将其设置为 nil)。

      另外注意,viewDidUnload 并不总是在 dealloc 之前被调用。所以你应该释放每个属性/变量都是dealloc,即使它也被释放并在viewDidUnload中设置为nil。为了确保在释放类时不会泄漏,该代码的 dealloc 函数应如下所示:

      - (void)dealloc {
          [myTableCell release];
          [myLabel release];
          [_myArray release];
          [myString release];
      
          [super dealloc];
      }
      

      将它们设置为 nil 也是可以接受的,但前提是您使用合成的 setter,因为这也会释放变量。

      self.myLabel =  nil;
      

      很好,但是

      myLabel = nil;
      

      漏水了。

    【讨论】:

    • myTableCell、myLabel 和 myString 是没有实例变量的属性,不可能说 [myTableCell release] 而且我知道 [self.myTableCell release] 是错误的。
    • 其实[myTableCell release]是正确的。这些 ivars 是隐式创建的。
    • 根据您使用的编译器版本,这些都可能有效。 @synthesize 为您创建一个 ivar - 您刚刚将 myArray ivar 重命名为 _myArray 但其他属性具有相同的名称 ivar。此外,如果你在dealloc 中,只要你不是多线程的,你“可以”摆脱[self.myTableCell release] ......但这过于复杂 - 现在,使用我之前描述的 setter 和 getter,并彻底阅读内存管理指南......或者使用 ARC - 它也适用于 iOS4 设备。
    • 当您创建一个属性并且没有显式创建实例变量时,会自动为您创建实例变量。
    • 所以即使我从不使用那些隐式创建的实例变量,我也应该释放它们?
    【解决方案2】:

    一般来说,如果您的 ViewController 在此期间没有被释放,您希望您的 viewDidUnload 释放可以在 viewDidLoad 中重新创建的任何内容。

    dealloc 中,您需要释放 ViewController 仍拥有的任何内容。你不能假设 viewDidUnload 被首先调用,所以要防御。

    还请记住,向 nil 发送消息没有害处 - 但向您不拥有的对象发送释放或多次向您拥有的对象发送释放有很多害处。

    由于您的属性是综合保留,您可以避免自己发送release,只需使用setter将它们设置为nil(self.property = nil),当然假设您没有在任何地方添加任何额外保留.

    注意在您的viewDidLoad 中,您已将一个新创建的对象显式分配给您的属性已合成的 iVar。不要这样做! 如果另一个对象在实例化和表示之间设置了属性,那么它将泄漏。仅当您确定这样做是正确的并且您已经处理了所有极端情况时才使用_ivar

    TL:DR - 在viewDidUnloaddealloc 中都使用self.property = nil,并且永远不要将新对象分配给_ivar,除非您首先检查它已经是nil 或准备释放以前的值。

    【讨论】:

    • self.myArray = [NSArrary alloc] initWithObjects:@"testObject", nil] 在 Xcode 中分析时显示泄漏。
    • self.myArray = [[[NSArray alloc] initWithObjects:@"testObject", nil] autorelease] 或更简单的self.myArray = [NSArray arrayWithObjects:@"testObject", nil]
    • 感谢您的回复,您能否详细说明为什么不应该将数组设置为 _ivar。我看到很多人在设置数组和其他对象时这样做。
    • 还有,数组等这些属性什么时候释放。我只是在 viewDidLoad 中初始化数组。我只是用它来评估整个班级的时间副本。这会导致问题吗?
    • 非常感谢,我不知道这有什么不同。我的属性在类文件而不是标题中,所以我想我在那里没问题,但现在这很有意义。
    猜你喜欢
    • 1970-01-01
    • 2011-02-20
    • 2011-07-01
    • 2011-01-22
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 2012-06-25
    相关资源
    最近更新 更多