【问题标题】:If you have an IBOutlet, but not a property, is it retained or not?如果您有 IBOutlet,但没有属性,是否保留?
【发布时间】:2011-07-28 06:06:27
【问题描述】:

我发现有关此问题的文档不清楚:

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

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

假设您肯定会在应用运行期间多次显式创建然后删除 BigView。所以:

对于 NIB 中的这些顶级项目之一,存在三种可能性

(1) 你根本没有任何类型的 IBOutlet。

(2) 您确实有一个连接的 IBOutlet - 但没有一个属性。

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

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

在 (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: Cheers 的行为

【问题讨论】:

  • 非常感谢。我想知道完全相同的问题!读完苹果文档后我很困惑,所以我完全不确定该相信什么。还要感谢 Jonah 的澄清。
  • 这很奇怪,呵呵——我同意你的看法。感谢投票,因为那个投票给了我“超能力”或这个网站上的东西!!!我是世界之王!!!

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


【解决方案1】:

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

【讨论】:

  • 我没有 dv,但是如果 IB 需要查看它,你肯定只需要制作一个出口,如果你想要 getter/setter 只需要一个属性?
  • 如果您需要一个插座,那是因为您计划保留对从 nib 文件创建的内容的引用。使用属性来管理该引用避免了上面提出的各种问题,并且还使内存管理更容易。当然,您可以直接使用 ivar,但任何属性都是如此。也许您的意思是,当您打算让除 self 之外的对象更改相关值时,您可能只使用属性,但这正是从 nib 加载对象时发生的情况。
  • @Joe Blow,我确实认为这是一个有趣的问题,但是由于像这样的主题往往会让初学者感到困惑,我想把最好的实用解决方案放在那里。我知道我发布的内容不是您要寻找的答案,如果有人因此而否决这个答案,那很好。
  • 使用属性真的能提高性能吗?我的印象是它为您提供了该变量的 getter 和 setter...我从不使用属性,除非我也有,而且我从未注意到性能上有什么不同(尽管我可能错了)。编辑:哦,等等,你的意思是不使用属性来获得稍快的性能吗?如果是这样,我明白了!!我也这样做!
  • @Joe 是的,我们在同一页面上......根据我的经验,我只在需要时使用属性,因为 a) 我总是被教导在需要时创建 getter 和 setter,并且 b)我不能为每个 var 都这样做!
【解决方案2】:

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

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

乔恩·赫斯正确还是弗里曼正确?

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

仍然强烈建议为所有 outlet 设置 setter 方法:

Resource Programming Guide, Nib Files

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

【讨论】:

  • 是的,它被保留了,你应该在完成后释放它(通常在dealloc 中)。实际上我过去使用过这种方法,但现在我为此使用属性,因为它对我的代码的未来维护者来说不太容易混淆。
  • 嗨,哈哈。感谢您的指导。事实上,我做了一个测试项目,它证明了这种情况。我会发布它。我很惊讶仅仅将 IB 元素连接到 IBOutlet 的行为实际上增加了一个保留。再次感谢和欢呼!抱歉,有些白痴否决了您的评论!
【解决方案3】:

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

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

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

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

[filesOwner setValue:loadedObject forKey:nameOfIBOutlet];

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

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

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

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


如果你为 nib 文件对象定义了 outlet,你应该总是定义一个 setter 方法(或声明的属性)来访问那个 outlet。 outlet 的 setter 方法应保留其值,而包含顶级对象的 outlet 的 setter 方法必须保留其值以防止它们被释放。

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


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

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

【讨论】:

  • 嘿 Joneh —— 简而言之,这是对 setValue:forKey: 行为的精彩解释,谢谢。 (正如我详细描述的那样,doco. 存在严重缺陷……如果没有你,我们会被塞满的。)干杯!
猜你喜欢
  • 2011-12-19
  • 1970-01-01
  • 1970-01-01
  • 2010-10-21
  • 2010-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多