我为什么要写[anView release],anView = nil;而不是[anView发布];?

时间:2009-04-30 08:25:12

标签: iphone cocoa-touch memory-management uikit

在某个地方我正在阅读 - 关于低内存警告并放弃一个不可见的视图及其所有子视图(=我觉得整个笔尖),你应该这样做:

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

    [super dealloc];
}

而不是

-(void)dealloc {
    [anView release];
    [someImageView release];

    [super dealloc];
}

在我调用release之后,将这些指针接到nil(=“no object”)的原因是什么?让我猜一下:其他一些方法可能因为某些原因(任何人可能发生这种情况的任何例子)得到了视图,然后发生了didReceiveMemoryWarning事件,并释放了一个当前不可见的整个笔尖+视图(即在multiview-app中)。一旦用户想要再次看到该视图,您将再次快速加载笔尖然后:它加载所有视图,连接插座,然后砰!你的另一个保留视图现在已经挂起,没有任何指针在内存块中的某个地方孤独,导致内存泄漏,直到你的应用程序崩溃。

正确/错误?

5 个答案:

答案 0 :(得分:14)

原则比UIView更普遍。实际上它比Objective-C / Cocoa -release方法更通用。它对C malloc() / free()内存函数也有效。

当您不再需要对象或任何内存区域时,首先释放/释放它。然后,为了确保不再使用它,您可以通过将nil分配给对象或将NULL分配给内存指针来清除访问此对象或内存区域的方法。

答案 1 :(得分:11)

  

其他一些方法可能会出于某种原因而保持观点

除非您自己调用dealloc,否则只有在保留计数为零时才会调用它。

请注意,在Objective-C中,向nil“对象”发送消息(通常)非常好。这样做会使程序暂停,但会忽略该消息。但是,您无法向释放的对象发送消息,这会导致崩溃。

因此,以下内容会给您一个错误:

[anView release];
[anView doSomething];

但是,这实际上是好的:

[anView release];
anView = nil;
[anView doSomething];

这是一个品味的问题,但对于上述情况,你可能实际上更喜欢崩溃你的程序,而不是想知道为什么没有执行某事......

另请参阅Apple的Sending Messages to nil中的Introduction to The Objective-C 2.0 Programming Language

答案 2 :(得分:4)

释放对象时调用-dealloc方法,之后不会执行对象上的其他方法。因此,将任何实例变量设置为nil在该对象之外没有任何影响。

如果你在类中的其他地方释放一个对象(不使用setter),那么将实例变量设置为nil以防止其他地方的代码向该地址发送消息是很重要的。

答案 3 :(得分:2)

我经常使用这种模式:

- (void) showHelp: (id) sender
{
    if (helpController == nil)
    {
        helpController = [[HelpController alloc] initWithNibName: @"Help" bundle: [NSBundle mainBundle]];
    }
    [self presentModalViewController: helpController animated: YES];    
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
    [helpController release];
    helpController = nil;
}

几乎无处不在,我分配了一个模态或其他“临时”的视图控制器。这样,如果我再次需要它,它会挂起,但如果内存不足则会消失。

答案 4 :(得分:1)

而不是进行expicit发布并设置为nil,如果您的访问者具有与之关联的属性yoc并执行以下操作作为更简洁的方法:

- (void) dealloc
{
    self.retainedProperty1 = nil;
    self.retainedProperty2 = nil;
    self.copiedProperty = nil;
    self.assignedProperty = nil;
}

通过这种方式,您可以拥有重复次数较少的代码,因为合成代码将为您处理您的版本。

编辑:我应该指出你的属性不能只读或者你得到编译器错误的原因显而易见:)