You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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属性强引用ViewController
  • NSViewController的representedObject是强引用属性,因此ViewController会反过来强引用Document实例
  • 这就形成了Document ↔ ViewController的双向强引用循环,导致两者在窗口关闭后无法被系统释放

Apple示例避免循环引用的原因

官方示例里,contentVC.representedObject指向的是content——也就是文档的数据模型(通常是独立于Document的纯数据对象,比如自定义模型类或Data),而非Document本身。此时的引用链是:

  • Document强引用content(数据模型)
  • Document强引用ViewController
  • ViewController强引用content(数据模型)

这条链里没有双向循环:当文档关闭时,NSDocumentController会释放对Document的引用,整个强引用链被打破,ViewController和content都会被正常回收。

补充:representedObject的属性特性

NSViewController的representedObject是强引用属性,其Objective-C声明为:

@property (strong) id representedObject;

这意味着只要你把Document实例赋值给它,就必然会触发循环引用——除非你在自定义ViewController时,将其改为弱引用(正如你已经采取的解决方式)。

总结

官方示例没有循环引用,本质是没有让视图控制器直接持有文档实例的强引用,而是持有文档的数据模型。你的实现因为误将Document本身赋值给representedObject,才产生了循环引用问题。

内容的提问来源于stack exchange,提问作者Daniel Higgott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:31:01