将 NSArrayController 的 managedObjectContext 设置为 nil 时崩溃

Crash when setting NSArrayController's managedObjectContext to nil

我有一个基于 NSDocument 的带有 Core Data 的 macOS 应用程序,从本质上讲,它一次只能打开一个文档。因此,当打开一个新文档时,我会关闭当前打开的文档。 所有与文档相关的 UI 都在一个单独的 window 控制器中,并且一切正常。

但我还有一个菜单栏项,它可以切换一个单独的 window,它显示有关文档的一些信息。 UI 是绑定到 NSArrayController 的简单 NSTableView。数组控制器的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 时导致崩溃。

我怎样才能安全地"deactivate"一个NSArrayController,或者改变它的managedObjectContext?

经过大量试验后,我想我发现 NSArrayController 在您调用 fetch(_:)preopareContent() 时会产生内存泄漏。它似乎保留了它的 managedObjectContext 并且永远不会释放它。即使所有其他对控制器的引用都已释放,我仍然可以在内存调试器中看到泄漏的实例。

我通过用常规 NSTableViewDataSource 实现替换绑定来解决这个问题。