iPhone - dealloc - Release vs. nil

24

想知道有经验的人能否更详细地解释一下这个问题。我已经看到过一些例子,但是我还是不太理解。

  [view release];

  view = nil;  

....在 (void) dealloc 内部。

这两者有什么区别,哪种更好?什么是最好的方法?

在进行 retainCount 测试时,我个人见过 nil 使计数从3降至0,但 release 只将其从3降至2。

5个回答

36

你可能见过这些:

1) [foo release];
2) self.bar = nil;
3) baz = nil;
  1. dealloc方法中,通过实例变量foo来访问对象并释放它。这样做会使得实例变量成为一个悬空指针。

  2. 在自定义属性的setter方法中,给self上的属性 bar 赋值为nil,会释放该属性当前持有的任何对象。如果属性的setter方法需要清理除了实例变量之外的其它资源,请使用这种方式。

  3. 将指向对象的指针baz赋值为nil,但不会释放该对象,导致内存泄漏。绝不要这样做。


所以在viewDidLoad里使用数字3不会释放分配对象的内存? - bbullis21
不,使用第3种方法永远不会释放内存,除非你在Mac OS X上使用垃圾回收的obj-C。 - PeyloW
执行self.bar = nil也可能导致内存泄漏。如果属性被定义为@retain,它将按预期工作;如果您将其定义为@copy,则会出现内存泄漏。 - AlBlue
6
@AlBlue认为,使用retaincopy并不会导致内存泄漏,因为它们在语义上都释放了属性之前引用的对象。唯一的区别是如何获得新值;ivar = [newValue retain];ivar = [newValue copy]二者皆可,均使用[ivar release]来释放旧值。 - PeyloW
请让我确认一下: "self.property = foo" 会经过合成的setter(释放旧值,保留新值),但是 "property = foo" 只是将一个新指针直接赋给属性字段,绕过了setter? - Bogatyr
8
使用2)可能存在危险,这就是为什么优先使用1)的原因。如果子类重写了setter,那么在子类中调用一个已经被调用了 dealloc 方法的方法。安全使用属性/实例变量的一般规则是:
  1. initdealloc 和 setters/getters 中直接使用实例变量。
  2. 其他所有访问都应该通过属性进行。
- Andrew

8

如果您没有使用属性(其中self.property = nil也会释放对象),那么您应该始终在释放后跟随将引用设置为nil的代码,就像您所概述的一样:

[view release]; view = nil;

原因是它可以避免使用无效的引用。虽然这种情况很少见,但确实可能发生。
在viewDidUnload中释放IBOutlets时更加重要 - 这是一个更现实的场景,其中由于内存警告而卸载视图可能导致引用失效,然后在重新加载视图之前,视图中的其他代码尝试使用引用。
基本上,这只是一个好习惯,如果你养成这个习惯,它会在某些时候为你避免崩溃。

所以,对于具有属性的ivars,我们可以这样做吗?
  • (void)dealloc { self.iVar = nil }
- Alex Nguyen
你可以使用setters在dealloc中将变量设置为nil,尽管过去曾经告诫你不要这样做以避免副作用。但是现在内部类变量可以自动创建,在必须使用setters的情况下,我想使用该方法在dealloc中将变量设置为nil已被认为是可以接受的。 - Kendall Helmstetter Gelner
你仍然可以引用合成的实例变量,在dealloc中不必使用setter。 - Luke Redpath
1
一个很重要的观点,实际上在dealloc中不应该使用setter方法。 - Kendall Helmstetter Gelner

2
@bbullis22,你看到引用被设置为nil后,保留计数从3下降到0。然后你要求'nil'的保留计数,这是零。然而,曾经被引用的对象保留计数仍然是-1(由于将引用设置为nil)。 使用release时,引用仍然指向同一对象,所以在这种情况下,你会看到保留计数从3下降到2。

1

就使用代码而言,在您的dealloc中,您不需要对属性进行赋值,只需要释放即可。

- (void)dealloc {
    [myProperty release]; // don't need to assign since you won't have the object soon anyway
    [super dealloc];
}

1
等等,那最后一行不应该是 [super dealloc] 吗? - zpasternack

0

我认为同时使用两者是一种安全保障。如果仅使用release会在引用计数管理出现问题时导致运行问题。您将释放一个对象,将其内存返还给系统,但指针仍然有效。

使用nil可以确保程序不会崩溃,因为向nil发送消息不会有任何影响。


你建议先调用哪个?在释放之前调用Nil还是反过来? - bbullis21
在释放对象之前赋值为 nil 意味着你将 release 发送给了 nil(因此没有释放对象)。将其赋值为 nil 是可选的(因为对象正在被释放,实例变量不应再被引用)。 - rpetrich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接