IBOutlet Work的readonly属性是否优先?

时间:2011-11-01 21:59:24

标签: objective-c cocoa-touch memory-management iboutlet

在我继承的代码中,我见过以下内容:

@property (readonly) IBOutlet UIImageView * bgImage;

当我期望保留记忆模型如:

@property (readonly, retain) IBOutlet UIImageView * bgImage;

我很困惑为什么第一个属性定义在不引起问题的情况下工作。

此外,dealloc中有一个release正如您所期望的那样:

-(void)dealloc
{
   [_bgImage release];
   [super dealloc];
}

如果有人能为此提出解释,我将不胜感激。我和原始开发人员谈过,他试图编写更简洁的代码,这就是为什么他在内存模型中省略了retain(似乎没必要)。

我想知道IBOutlet是否基本上被视为ivar IBOutlet语句,因为它是只读的(不使用setter,因此默认的assign memory模型没有区别)。

如果永远不会改变IBOutlet,那么使用没有内存模型的readonly属性实际上是定义属性的更好方法吗?

2 个答案:

答案 0 :(得分:7)

iOS上的nib加载器在nib中创建对象,然后自动释放它们。当它建立与出口的连接时,它使用setValue:forKey:,它将调用该密钥的setter方法。如果未定义任何setter,例如IBOutletreadonly属性,则在分配之前,对象将保留 。 (这是资源编程指南中Managing Nib Objects in iOS的解释。)

实际上,无论插座是声明为retain还是assign,另一端的对象都是由具有插座的对象所拥有。它可以通过setter方法保留,也可以在找不到setter时由setValue:forKey:保留。由于在第二种情况下没有其他可能的所有者,您可以将具有插座的对象视为所有者。因此,应该在dealloc中释放nib中的对象。

我同意你的看法,应该通过更改属性属性以包含retain来明确显示此内存条件。*它是否readonly似乎无法生成差异(但见下文)。从概念上讲,是的,该对象是只读的,因此是否明确地将其标记为取决于您是否认为它是IBOutlet的适当记录。

更新: Paul.s的评论促使我做了一个快速测试。我创建了一个UIView子类,用于记录其allocretainreleaseautorelease个调用,将其实例粘贴到一个笔尖中,并给出了app通过属性委派IBOutlet

手动计算引用计数活动,当属性为(readwrite, assign)时,实例出现了净0计数。当属性被推荐为(readwrite, retain)时,它是净+1,当(readonly, assign)时,。所有这些都与预期的一样 - 当它为(readwrite, assign)时,分配设置器用于建立连接,并且不进行保留。当它为readonly时,连接机制会依赖于自己的保留。

最有趣的是,当我试图通过使用声明为(readwrite, assign)的属性更改此视图的背景颜色来崩溃应用程序时(即,当它可能已被释放时),我看到最后一次调用{{1弹出。

我认为这归结为:遵循Apple的推荐 - 他们知道幕后发生了什么,并且(除了错误)不会引导你做错。

(另一件需要注意的事情是,一如既往,担心绝对引用计数并不会非常有用 - 计数在一两个点上一直上升到6个,在二十几个电话中retainretain - 您只需要担心直接导致的保留和释放。)


*当然,这在ARC下有所改变。我转述的信息在" Legacy Patterns"本章的一节。在ARC下,建议releaseIBOutlets,除非它们是顶级,在这种情况下,它们应为weak。这样做意味着您依赖于视图层次结构(保留其子视图的视图)来维护自己。

答案 1 :(得分:2)

我已经向Apple报告了一个错误,即如果您创建IBOutlet实例变量而不是属性,那么Xcode仍将自动创建dealloc等版本。对于iOS应用程序,Xcode似乎总是为IBOutlet创建版本,无论其是否正确。 / p>

人员我不喜欢属性IBOutlet,因为它意味着你将它们声明为readwrite,这意味着它们被记录为readwrite,但大多数时候(几乎总是),IBOutlet在概念上应该是只读的。显然,他们必须先读写才能设置。