将NSDocument设为NSViewController的representedObject时如何避免循环引用
为什么Apple文档类应用示例无循环引用,而我的嵌套SplitVC实现出现了?
核心差异:representedObject的赋值对象不同
先对比两段关键代码:
Apple官方示例代码片段
if let contentVC = windowController.contentViewController as? ViewController { contentVC.representedObject = content // 赋值的是文档的**数据模型content**,而非Document实例 contentViewController = contentVC }
你的实现代码片段
if let vc = item.viewController as? ViewController { vc.representedObject = self // 赋值的是**Document实例本身** contentViewController = vc }
循环引用的根源
在你的代码中:
Document通过contentViewController属性强引用ViewControllerNSViewController的representedObject是强引用属性,因此ViewController会反过来强引用Document实例- 这就形成了
Document ↔ ViewController的双向强引用循环,导致两者在窗口关闭后无法被系统释放
Apple示例避免循环引用的原因
官方示例里,contentVC.representedObject指向的是content——也就是文档的数据模型(通常是独立于Document的纯数据对象,比如自定义模型类或Data),而非Document本身。此时的引用链是:
Document强引用content(数据模型)Document强引用ViewControllerViewController强引用content(数据模型)
这条链里没有双向循环:当文档关闭时,NSDocumentController会释放对Document的引用,整个强引用链被打破,ViewController和content都会被正常回收。
补充:representedObject的属性特性
NSViewController的representedObject是强引用属性,其Objective-C声明为:
@property (strong) id representedObject;
这意味着只要你把Document实例赋值给它,就必然会触发循环引用——除非你在自定义ViewController时,将其改为弱引用(正如你已经采取的解决方式)。
总结
官方示例没有循环引用,本质是没有让视图控制器直接持有文档实例的强引用,而是持有文档的数据模型。你的实现因为误将Document本身赋值给representedObject,才产生了循环引用问题。
内容的提问来源于stack exchange,提问作者Daniel Higgott
相关产品推荐
相关产品推荐

