我有一个带有Core Data的基于NSDocument
的macOS应用,其本质上一次只能打开一个文档。因此,当打开一个新文档时,我将关闭当前打开的文档。所有与文档相关的UI都位于单独的窗口控制器中,并且一切正常。
但是我还有一个菜单栏项目,可切换一个单独的窗口,该窗口显示有关文档的一些信息。 UI是绑定到NSTableView
的简单NSArrayController
。当前文档更改时,将设置阵列控制器的managagedObjectContext
属性。这总是会导致EXC_BAD_INSTRUCTION
崩溃。
为了缩小问题的范围,我完全删除了所有绑定以及对数组控制器的任何其他操作。崩溃不见了。我还用代码创建了一个新的testArrayController
,以查看在那里发生了什么,并确定我可以重现崩溃:
let testArrayController = NSArrayController()
var document: Document? {
didSet {
if document != nil {
testArrayController.managedObjectContext = document?.managedObjectContext
testArrayController.prepareContent() // <---- this causes the crash later on
} else {
testArrayController.managedObjectContext = nil
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
testArrayController.entityName = "MyEntity"
...
}
似乎调用prepareContent()
会以某种方式将数组控制器锁定到特定的ManagedObjectContext,并在将其设置为nil时导致崩溃。
如何安全地“停用” NSArrayController
或更改其managedObjectContext?
[经过大量的实验,我想我发现,只要您调用NSArrayController
或fetch(_:)
,preopareContent()
就会产生内存泄漏。似乎它保留了它的managedObjectContext
而从不释放它。即使已经释放了对控制器的所有其他引用,我仍可以在内存调试器中看到泄漏的实例。
我通过用常规的NSTableViewDataSource
实现替换绑定来解决此问题。