【问题标题】:Does readonly property for IBOutlet Work and would it be Preferable?IBOutlet 的 readonly 属性是否有效,它是否可取?
【发布时间】:2011-12-19 21:10:13
【问题描述】:

在我继承的代码中,我看到了以下内容:

@property (readonly) IBOutlet UIImageView * bgImage;

当我期望保留内存模型时:

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

我很困惑为什么第一个属性定义可以正常工作而不会引起问题。

此外,dealloc 中有一个 release,正如您所料:

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

    iOS 上的 nib 加载器在 nib 中创建对象,然后自动释放它们。当它与插座建立连接时,它使用setValue:forKey:,它将调用该键的setter 方法。如果没有定义设置器,例如当IBOutletreadonly 属性时,对象在被分配之前无论如何 被保留。 (这是资源编程指南中Managing Nib Objects in iOS 的释义。)

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

    我同意你的观点,应该通过将属性属性更改为包含retain 来明确此内存条件。* 无论它是否为readonly 似乎都没有区别(但是,请参见下文)。从概念上讲,是的,该对象是只读的,因此是否明确标记它取决于您是否认为通过它是 IBOutlet 的事实适当地记录了这一点。

    更新: Paul.s 下面的评论促使我进行了快速测试。我创建了一个UIView 子类来记录它的allocretainreleaseautorelease 调用,将它的一个实例插入一个笔尖,并通过一个属性给应用程序委托一个IBOutlet

    手动统计引用计数活动,当属性为 (readwrite, assign) 时,实例的净计数为 0。当属性被声明为推荐方式时,它是净 +1,(readwrite, retain),当它是 (readonly, assign) 时,也是。所有这一切都与预期的差不多——当它是(readwrite, assign) 时,分配设置器用于建立连接,并且不进行保留。当它是readonly 时,连接机制会退回到自己的保留上。

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

    我认为这归结为:遵循 Apple 的建议——他们知道幕后发生的事情,并且(除非出现错误)不会误导您。

    (要带走的另一件事是,与往常一样,担心绝对引用计数不会非常有用——在两次调用retainrelease -- 你只需要担心你直接导致的保留和释放。)


    *当然,这在 ARC 下会发生变化。我解释的信息在其章节的“传统模式”部分。在 ARC 下,建议将 IBOutlets 设置为 weak,除非它们是顶级的,在这种情况下它们应该是 strong。这样做意味着您依赖于视图层次结构(视图保留其子视图)来维护自身。

    【讨论】:

    • whether the outlet is declared as retain or assign, the object at the other end is owned by the object with the outlet(这不是很清楚)只有当它设置为readonly时才这样吗?如果是(assign, readwrite),那么肯定会使用非保留设置器并且不会使用retain? - 我只提到这是你答案中唯一有点模棱两可的部分
    • 我想是的......这肯定是它似乎在说什么。
    • @Paul.s:查看我的更新——我决定手动计算参考活动,我认为结果很有启发性。
    • 很好的好奇调查
    • @Sam:我认为您应该遵循 Apple 的建议:(readwrite, nonatomic, retain)(正如您所说,您可以省略明确的 readwrite)。这意味着不要不尊重你的同事,简洁当然有助于提高可读性,但有时写出每个人都期望的东西更重要。如果他按照推荐的方式来做,你就不必花任何时间去思考其中的含义了。虽然这是一件有趣的事情,但您可能在那段时间完成了(更重要的)事情。
    【解决方案2】:

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

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

    【讨论】:

    • 可以在公共接口中声明@property (nonatomic, readonly),在类扩展中声明@property (nonatomic) IBOutlet
    猜你喜欢
    • 2010-11-16
    • 2011-03-26
    • 2019-09-18
    • 1970-01-01
    • 2011-07-28
    • 2010-12-04
    • 2012-01-05
    • 1970-01-01
    • 2013-06-24
    相关资源
    最近更新 更多