16

我是一位经验丰富的 iOS 开发人员,我决定尝试一些 AppKit 开发。我在 API 方面进行了一些调整,但除此之外,我发现 OS X 开发是,容我们说,“熟悉”。

我一直在 Interface Builder 中构建我的 AppKit UI,并注意到当我使用 WYSIWYG 编辑器在我的代码文件中创建属性时,Apple 正在创建以下内容:

@property (assign) IBOutlet NSTableView *tableView;

我觉得这很好奇,因为 iOS 中默认的做事方式会导致我这样做:

@property (nonatomic, retain) IBOutlet NSTableView *tableView;

我意识到,在 Mac 开发中,我没有在移动设备上那样的内存限制,在移动设备上,视图可能会被卸载,并且可能需要对 UI 元素的强引用。

在 AppKit 案例中,我可以很好地假设我的 UI 元素将始终存在,除非我摆弄视图层次结构并将其从其父视图中删除。为了防止无意中访问悬空指针,在任何时候都有一个强引用似乎是谨慎的。

为什么 Apple 在这里创建一个弱引用,而不是一个强引用?

我是否通过使用强引用(但在 中正确释放dealloc)来为一些意想不到的后果做好准备?这里有一些我想念的模式吗?

4

1 回答 1

16

作为文件的所有者,您应该拥有 nib 中的所有顶级对象。您通常不需要拥有这些对象中的任何对象,因为父对象将拥有其子对象;例如,一个窗口将拥有它的视图。

AppKit 的 nib 加载器代表文件所有者隐式保留所有顶级对象。(这在@property、合成访问器和 ARC 存在之前是有意义的。)因此,即使相关属性是weakorunsafe_unretained(后者是 的同义词assign),所有者实际上也将拥有顶级对象。如果你反过来创建这些属性strong(aka retain),那么 FO 对每个对象都有两个所有权:隐式所有权和strong-property 所有权。

假设您使用手动引用计数,您可以释放 中的隐式所有权awakeFromNib,但这只是成功了。只要您在加载 nib 后不打算替换任何这些对象(例如,将一个表视图换成另一个表视图),一个unsafe_unretained属性就可以正常工作,而无需多余的保留或任何已完成的工作。

unsafe_unretainedassign但是,出于某种原因,将其命名为(并且该名称优先于对象属性)。返回 window-and-its-views 示例,假设您拥有一个窗口并且知道它的一个视图。视图的父视图可能是它的唯一所有者,因此,当您关闭窗口(或用户关闭它)时,视图将被释放并因此被释放。如果您的视图属性是unsafe_unretained/ assign,您仍然知道这个现已死亡的对象,并且尝试向视图发送消息可能会导致崩溃或异常。

您应该切换到 ARC 并将属性声明为weak. 这样,就不会创建多余的所有权,并且该属性将nil在视图终止时自动设置为,从而防止过度释放崩溃。

(如果您不是文件的所有者,那么这些都不适用于您,您可能应该按照您认为合适的方式声明您的属性。weak或者strong可能是一个不错的选择,这取决于您如何看待您的所有权层次结构以及您使用什么样的对象'正在参考。)

在 iOS 上,UIKit 的作者去掉了现在有问题的隐式保留。您应该编写自己的所有权;如果你想从一个 nib 或 storyboard 中拥有一个对象,你写一个strong属性,如果你只是想知道它,你写一个weakunsafe_unretained一个,正如你所期望的那样。

TL;DR: 歇斯底里的原因。

于 2012-08-30T04:10:18.707 回答