在我继承的代码中,我见过以下内容:
@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属性实际上是定义属性的更好方法吗?
答案 0 :(得分:7)
iOS上的nib加载器在nib中创建对象,然后自动释放它们。当它建立与出口的连接时,它使用setValue:forKey:
,它将调用该密钥的setter方法。如果未定义任何setter,例如IBOutlet
为readonly
属性,则在分配之前,对象将保留 。
(这是资源编程指南中Managing Nib Objects in iOS的解释。)
实际上,无论插座是声明为retain
还是assign
,另一端的对象都是由具有插座的对象所拥有。它可以通过setter方法保留,也可以在找不到setter时由setValue:forKey:
保留。由于在第二种情况下没有其他可能的所有者,您可以将具有插座的对象视为所有者。因此,应该在dealloc
中释放nib中的对象。
我同意你的看法,应该通过更改属性属性以包含retain
来明确显示此内存条件。*它是否readonly
似乎无法生成差异(但见下文)。从概念上讲,是的,该对象是只读的,因此是否明确地将其标记为取决于您是否认为它是IBOutlet
的适当记录。
更新:
Paul.s的评论促使我做了一个快速测试。我创建了一个UIView
子类,用于记录其alloc
,retain
,release
和autorelease
个调用,将其实例粘贴到一个笔尖中,并给出了app通过属性委派IBOutlet
。
手动计算引用计数活动,当属性为(readwrite, assign)
时,实例出现了净0计数。当属性被推荐为(readwrite, retain)
时,它是净+1,当(readonly, assign)
时,也。所有这些都与预期的一样 - 当它为(readwrite, assign)
时,分配设置器用于建立连接,并且不进行保留。当它为readonly
时,连接机制会依赖于自己的保留。
最有趣的是,当我试图通过使用声明为(readwrite, assign)
的属性更改此视图的背景颜色来崩溃应用程序时(即,当它可能已被释放时),我看到最后一次调用{{1弹出。
我认为这归结为:遵循Apple的推荐 - 他们知道幕后发生了什么,并且(除了错误)不会引导你做错。
(另一件需要注意的事情是,一如既往,担心绝对引用计数并不会非常有用 - 计数在一两个点上一直上升到6个,在二十几个电话中retain
和retain
- 您只需要担心直接导致的保留和释放。)
*当然,这在ARC下有所改变。我转述的信息在" Legacy Patterns"本章的一节。在ARC下,建议release
为IBOutlets
,除非它们是顶级,在这种情况下,它们应为weak
。这样做意味着您依赖于视图层次结构(保留其子视图的视图)来维护自己。
答案 1 :(得分:2)
我已经向Apple报告了一个错误,即如果您创建IBOutlet实例变量而不是属性,那么Xcode仍将自动创建dealloc等版本。对于iOS应用程序,Xcode似乎总是为IBOutlet创建版本,无论其是否正确。 / p>
人员我不喜欢属性IBOutlet,因为它意味着你将它们声明为readwrite,这意味着它们被记录为readwrite,但大多数时候(几乎总是),IBOutlet在概念上应该是只读的。显然,他们必须先读写才能设置。