我需要在dealloc中释放吗?

3
在我学习iPhone开发的书中,他们使用Interface Builder来利用IBOutlet实例。一个例子就是UIButton。所以他们在结构体中添加了这样一个东西:
 IBOutlet UIButton *whateverButton;

然后他们在.h文件中为每一个属性添加@property,在.m文件中添加@synthesize

然后他们在.m文件的dealloc中包含一个release。两个问题:

  1. 释放是否必要?难道不是所有属性都已经自动处理了吗?
  2. 为了调试目的,如何检查引用计数以查看发生了什么情况?
3个回答

5

发布是否必要?难道不是所有属性都已经自动处理了吗?

如果属性被保留,那么释放就是必要的。当您声明一个 @property 并且 @synthesize 它时,您得到的只是访问器,在 dealloc 中没有特殊的自动行为。

另外,IBOutlet 没有任何神奇之处 - 它只是 Interface Builder 用来查看您希望在 IB 中出现哪些属性的标记。它只是一个空的宏,单击 IBOutlet 关键字以查看其定义:

#ifndef IBOutlet
#define IBOutlet
#endif

同样适用于IBAction,它扩展为void
“我该如何检查引用计数以查看发生了什么,出于调试目的……?”
当我需要调试内存管理时,通常会在dealloc方法中设置断点或在那里记录一个字符串。在可能对其进行一些奇怪操作的调用周围记录对象的retainCount也有所帮助。
这也可能有助于查看@synthesize指令如何创建访问器。当您声明保留的@property并要求编译器@synthesize它们时,您会得到类似于以下内容:
@property(retain) NSString *foo;
@synthesize foo;

- (void) foo {
    return foo;
}

- (void) setFoo: (NSString*) newFoo {
    // Try to think what would happen if this condition wasn’t
    // here and somebody called [anObject setFoo:anObject.foo].
    if (newFoo == foo)
        return;
    [foo release];
    foo = [newFoo retain];
}

这不是完全相同的东西,但已经足够接近了。现在应该更清楚为什么你应该在dealloc中释放。


所有的笔记都非常好,特别是那些关于IBOutlet的内容,我可能从未学过。谢谢。 - Dan Rosenstark
SO上的几个人告诉我,记录retainCount是不可靠的。(我自己没有尝试过。)这里有一个必要的链接:http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH - andyvn22
我从未遇到过它的任何问题。但是经过再次考虑,我没有在dealloc中记录它,我总是在某些其他调用周围记录它。(我会更新答案。) - zoul

5

属性不会被"自动处理"。最接近的情况是,合成访问器会正确处理它们的内存管理职责。但这只是针对那些访问器而言。属性只是在类中声明可访问的"东西"的一种方式。除此之外,它们并没有得到太多特殊的处理。它不会开启某种垃圾回收机制。所以,是的,释放是必要的。

如果您想检查运行中的应用程序是否存在泄漏或未释放的内存,您应该使用像Instruments这样的调试工具。我不建议直接查看引用计数,因为它几乎是非常无用的——在任何时候都不能保证引用计数将是您所期望的,并且这并不一定表示问题。

您应该阅读苹果公司的Cocoa内存管理规则。一旦您掌握了这个规则,它就很简单了。我不一定建议先阅读其他指南,因为微妙的错误陈述可能会导致您走错方向(例如,属性将为您释放的想法可能来自于听到某人错误地陈述它们的工作原理)。


谢谢Chuck,这很有帮助。我在SO上看到过这个想法,但我肯定/希望我引用或误解了它。 - Dan Rosenstark
是的,我现在明白了。我以为setter正确地做了保留/释放,就有点像“某种垃圾回收”。它只是帮我节省了在setter中进行保留/释放的工作。 - Dan Rosenstark

3

发布是否必要?难道所有属性不是已经自动处理了吗?

这取决于属性的实现方式。如果它是自动实现的(使用@synthesize),则属性将在setter中保留其值,并在设置为其他值时释放它。如果您刚开始学习Obj-C和Cocoa,您应该阅读有关内存管理惯例的文档。我在我的博客上发布了一篇文章介绍了它们,还有其他很多资源。

如何检查引用计数以调试目的?

您可以检查NSObject的retainCount属性。相关信息请点击这里。对于高级调试目的,有NSZombieEnabled环境标志,它会导致所有释放消息不会减少引用计数,但在访问本应被释放的对象时记录错误。


不取决于属性的实现方式。如果它是一个retain属性,在dealloc中必须释放它。 - Chuck
谢谢。所以我想我把设置器(他们称之为monger?记不清了)正确设置与不需要显式调用保留混淆了。现在我看到我的错误了。 - Dan Rosenstark
@chuck:弱引用怎么样? - Johannes Rudolph
如果你在谈论__weak,它在非垃圾回收应用程序中没有任何影响。尽管弱引用通常是一个assign属性的合理选择,这种情况下你不需要释放它(因为你没有保留它)。 - Chuck
我在谈论赋值(assign)。我本可以更加准确地描述这个过程,以及dealloc和release(我曾经看到过通过将属性设置为nil来实现dealloc的情况,但我不想让任何人感到困惑)。不过你说得很好。 - Johannes Rudolph

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