如果您有IBOutlet但不是属性,是否保留?

时间:2011-04-02 12:57:52

标签: iphone cocoa-touch memory-management interface-builder nib

我发现这个问题的文档不清楚:

假设您正在使用iOS(不是Mac案例,不需要提及差异)。说严格是4.0+(不需要提及旧操作系统的差异)。假设我们严格自动加载NIB。

假设你有一个UIViewController,BigView。假设NIB文件中有十几个所谓的“顶级”项目......可以是自定义控件,图像或其他任何内容。

假设你肯定会在应用程序运行期间多次显式创建然后摆脱BigView。所以:

对于NIB中的其中一个顶级项目,有三种可能性

(1)根本没有任何形式的IBOutlet。

(2)你有一个连接的IBOutlet - 但不是属性。

(3)你确实有一个连接的IBOutlet属性(为了避免混淆,我们会说保留属性)。

那么当BigView发布时,该项会发生什么?

在(3)的情况下,您必须明确释放。如果你不这样做,它将在视图消失后徘徊。没问题。

在(1)的情况下,我假设(但是任何人都可以确认?)当BigView消失时该项目将被释放。

在(2)的情况下,不清楚会发生什么.......

查看众所周知的参考链接:http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html这是非常可疑的:

“在iOS中,nib加载代码使用setValue:forKey:方法重新连接每个插座。该方法类似地寻找一个合适的访问器方法,并且[如果没有一个,那么发生了什么?告诉我们APPLE。 ..]当失败时,它会回到其他方式...... [GOOD GRIEF!]“

并查看此文档:http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html并向下滚动到“Nib Object Retention”

所以......

“nib文件中的对象创建时保留计数为1,然后自动释放”很棒..

但是等等!读几句话......

但是,...如果没有可用的setter方法,则使用可用的setter方法或默认保留对象

他们在说什么?

他们是否意味着如果没有可用的setter(ivar,但没有属性),那就是 AGAIN RETAINED(除了前一条款中提到的“保留”)---或者,他们只是重复自己,即“默认保留对象”是他们之前刚刚讨论的“保留”(“保留计数为1然后自动释放”)。

为什么他们甚至会提到自动释放,如果不是这样的话呢?

确实 - 如果有人真正明确知道这个问题的答案...... 你怎么知道?!?你问过DTS,还是通过测试,或者?我建议,关键文档(刚刚粘贴)是非常不明确的。

再次 - 如果您有一个IBOutlet,但不是属性,则连接到“顶级”对象.. 您负责释放它吗?它保留了吗?在那种情况下?

就此而言....仅仅在情况(1)中,当BigView消失时,它会被释放吗?我当然会认为情况确实如此,但谁知道呢?

问题是如果你使用IBOutlet iVar会发生什么,而不是属性......

我愚蠢地从来没有想过这个/假设太多,有没有人有决定性的答案?干杯!!


为了记录,我做了一个测试项目。

事实上(令我惊讶的是)将IB元素连接到IBOutlet的行为实际上显然增加了一个保留

(我只能从伪劣的文件中假设,在那种情况下你会特别得到:保留,自动释放,保留 - 导致一个保持平衡。)

所以,这就是答案。

我将发布演示项目。我也引导任何读者阅读下面的Jonah的答案,它完美地解释了setValue的行为:forKey:干杯

3 个答案:

答案 0 :(得分:11)

我看不出是什么导致了这么多混乱,我认为“Nib Object Retention”文档准确地解释了会发生什么。让我们分解一下,然后看看会发生什么:

  

nib文件中的对象创建时保留计数为1,然后自动释放。

ClassLoadedFromNib *loadedObject = [[[ClassLoadedFromNib alloc] initWithCoder:coder] autorelease];

  

在重建对象层次结构时,UIKit使用setValue:forKey:方法重新建立对象之间的连接,

[filesOwner setValue:loadedObject forKey:nameOfIBOutlet];

  如果没有可用的setter方法,

使用可用的setter方法或默认保留该对象。

iOS中-setValue:forKey:的默认行为大致是

//lazy pseudocode
if ([self respondsToSelector:@selector(@"setKeyName:")]) {
  [self setKeyName:value];
}
else {
  object_setIvar(self, _keyName, [value retain]);
}

有关更多详细信息,请参阅键值编程指南。除非您的文件所有者对象覆盖-setValue:forKey:(或+accessInstanceVariablesDirectly-setValue:forUndefinedKey:),否则期望按上述方式管理对象所有权。


  

如果为nib-file对象定义出口,则应始终定义用于访问该出口的setter方法(或声明的属性)。出口的Setter方法应保留其值,并且包含顶级对象的出口的setter方法必须保留其值以防止它们被释放。

允许nib加载将ivar直接设置为外部保留的对象令人困惑。不要那样做。为您的商店提供setter方法,以便明确加载对象的所有权。


  

如果未将顶级对象存储在出口中,则必须保留loadNibNamed:owner:options:方法返回的数组或数组内的对象,以防止这些对象过早释放。

未连接到插座的对象已自动释放。保留它们或从-loadNibNamed返回的数组:owner:options:如果您打算稍后尝试访问它们。

答案 1 :(得分:2)

这是一个有趣的问题,但由于文档含糊不清,我认为最好的计划(以及我认为Apple推荐的计划)是让所有商店保留属性。你确切知道在这种情况下会发生什么,并且没有理由做其他任何事情。

答案 2 :(得分:0)

案例1)如果对象没有被任何东西保留,它将在下一次自动释放池排放时被释放。

案例2)在上面提到的答案中,Jon Hess已经描述了(参考文档)在这种情况下Mac OS X和iOS之间的差异。

  

Jon Hess是正确还是Freeman正确?

在iOS案例中,Hess和Freeman都说该对象将被保留。他们之间没有矛盾。

强烈建议为所有网点设置setter方法:

Resource Programming Guide, Nib Files

  

如果为nib-file定义出口   对象,你应该总是定义一个   setter方法(或声明的属性)   用于访问该插座。二传手   出口的方法应保留   他们的价值......