使用 loadNibNamed: 方法时是不是需要释放 IBOutlets?

Posted

技术标签:

【中文标题】使用 loadNibNamed: 方法时是不是需要释放 IBOutlets?【英文标题】:Do I need to release IBOutlets when using loadNibNamed: method?使用 loadNibNamed: 方法时是否需要释放 IBOutlets? 【发布时间】:2008-12-19 23:35:46 【问题描述】:

我有一个 .xib 文件,其中包含一个 UIView 和 2 个 UILabel 子视图,这些子视图链接到一个名为 Note 的类,并适当地为每个标签分配了插座,该类的定义包含以下内容。

@interface Note : UIView 
    IBOutlet UILabel *time;
    IBOutlet UILabel *content;

我正在使用以下代码构建它

NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"Note" owner:self options:nil];
note = [nibViews lastObject];
[self addSubview:note];

现在,在我的 Note 类 dealloc 阶段,我既没有发布时间也没有发布内容,但我想知道我是否应该这样做?

- (void)dealloc 
    [super dealloc];

我假设我不这样做是因为我没有在代码中的任何位置明确保留这些对象,并且我没有将它们合成到 getter/setter 中。但是我对 nib 取消归档的了解不够多,不知道是否应该在我的 dealloc 阶段释放这些?

【问题讨论】:

【参考方案1】:

即使您编写或合成访问器方法,您也应该发布一个 IBOutlet。 NIB 生命周期文档说,虽然未归档对象最初设置为自动释放,但当 UIKit 连接所有 IBOutlet 连接绑定时,它们的保留计数会增加 1。因此,您需要在完成后通过 release 手动递减。

UIKit 会这样做并不明显,因此您可能会认为您可以关闭 setter/getter 方法并相信一切都是自动释放的。但事实并非如此。

请注意,Interface Builder 模板明确发布任何 IBOutlets,因此您添加的任何内容都应同样处理。

【讨论】:

【参考方案2】:

这对 iPhone 来说是正确的;不过在 Mac 上是不正确的。

但是,您可能需要重新编写此代码。假设视图将是从 nib 加载的最后一个对象是不安全的。相反,我建议您将其连接到视图控制器中的“note”插座,或者扫描列表以查找属于 Note 子类的对象。 (如果您要加载多个便笺并使用出口选项,请确保在加载另一个便笺之前添加一个便笺。)

【讨论】:

你的意思是我不能保证它会是最后一个对象?你的意思是因为它可以按你想要的任何顺序订购一个 nib 的***,或者在取消归档时可以从界面生成器中显示的顺序更改? 不保证解压时的顺序。例如,在 iPhone OS 2.1 和 2.2 之间,加载时放置在 xib 中的单个 UITableViewCell 在数组中的不同位置返回(即使只有一个对象,loadNibNamed 返回的数组中也有多个元素)。【参考方案3】:

您确实需要释放它。见

“然而,当它重建对象层次结构时,UIKit 使用 setValue:forKey: 方法重新建立对象之间的连接,该方法使用可用的 setter 方法,如果没有可用的 setter 方法,则默认保留对象。”在Nib Object Retention

换句话说,因为你没有将这些条目指定为@property(它隐式声明了一个setter),或者直接提供了一个setter,所以没有可用的setter方法,本段的最后部分适用——对象默认保留。

你应该在你的 dealloc() 方法中,将所有 IBOutlets 设置为 nil 使用

self.outletName = nil;

如果没有定义 setter,那么 setValue 将自动释放旧值(如果在线程中运行,请确保您有一个 NSAutoreleasePool)。如果定义了 setter,它将执行您定义的任何行为。无论哪种方式,设置为 nil 都会做正确的事情,并确保您没有内存泄漏。不要这样做

outletName = nil;

这将直接设置成员变量,并绕过调用setValue。

详情请参阅 NSObject setValue:forKey 的文档。

运行性能工具(泄漏)不会显示泄漏,但您可以通过查看当前运行的分配内存总量来验证是否确实存在泄漏。

cfThe Airsource - Memory Management and NIBs

【讨论】:

self.outletName = nil;不,不要不要这样做;你不应该在 dealloc 中使用访问器方法。 Re “换句话说,因为你没有将这些条目指定为@property”:声明一个属性与它无关。重要的是访问器本身的存在与否,而不是语法糖。 同意并编辑。我的意思是,他甚至没有通过隐藏方法将访问器声明为@property,但这并没有很好地体现出来。 关于存取方法,你在我的博客上也提出了这一点,我仍然不同意。【参考方案4】:

除非您将 IBOutlets 声明为属性并将它们合成为 ivars,否则您将无法将它们从内存中取出:

@interface Note : UIView 
    IBOutlet UILabel *time;
    IBOutlet UILabel *content;


@property (nonatomic, retain) IBOutlet UILabel *time;
@property (nonatomic, retain) IBOutlet UILabel *content;

@end


@implementation Note
@synthesize time, content;

// your methods

- (void)dealloc 
     [time release], time = nil;
     [content release], content = nil;
     [super dealloc];


@end

【讨论】:

【参考方案5】:

我相信你是对的。有关更多详细信息,请参阅下面的文档链接。

文档:

The Nib Object Lifesycle Dicussion Thread at Apple support boards Another discussion thread

【讨论】:

答案不正确,正如该线程其他帖子中所解释的以及 Apple 所记录的那样。 这个答案对于 Mac OS X 是正确的,但对于 ios 是不正确的。查看“***对象”下的此链接。 developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/…

以上是关于使用 loadNibNamed: 方法时是不是需要释放 IBOutlets?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ios 中使用 UI NIB 而不是 loadNibNamed 来自定义 UI 表格视图单元格?

使用方法[NSBundle loadNibNamed:xibName owner:[NSApplication sharedApplication]]加载Nib时如何传递参数?

使用 loadNibNamed:owner:topLevelObjects: 是不是允许***插座中的弱引用?

使用 loadNibNamed 时崩溃

使用 loadNibNamed 加载视图时,如何在 UIView 上调用便利初始化程序?

在为自定义视图调用 NSBundle(使用 loadNibName)后访问 IBOutlets 的最佳方法