Search code examples
xcodecore-datainterface-buildercocoa-bindings

What is the new way of binding an NSArrayController to the managed object context of a Core Data document?


Before Xcode went and added Storyboards for OS X apps you could connect an array controller to your document's managed object context by binding the Managed Object Context of the array controller to File's Owner with a Model Key Path of managedObjectContext. With storyboards there is no more File's Owner so where do you get the context from now?

Apple's documentation is behind in this area and there aren't any obvious places to bind to in Xcode. Obviously I can just fall back to a non-storyboard route and use the old method, but there must be a new way of doing it.


Solution

  • So I have the answer from Apple. This is for Document based Core Data apps, the code is all in Swift but the idea is the same in Objective-C you just have to translate it.

    The first answer they gave me was to bind the array controller to the view controller running the view with a model key path of self.view.window.windowController.document.managedObjectContex. The sample I was shown used this method and had no error messages at all, it was however a single view controller inside the window controller with one array controller. My setup is a window to a tab view to the views with two array controllers in the one scene. I was still getting Cannot perform operation without a managed object context once each time a new document was opened or created. The second solution, that worked for me was to still bind the array controller to the view controller but with a model key path of self.representedObject.managedObjectContext and then to add to the end of the document class's makeWindowControllers() function:

    override func makeWindowControllers() {
    ……
        let tabViewController = windowController.contentViewController as NSTabViewController
        for object in tabViewController.childViewControllers {
            let childViewController = object as NSViewController
            childViewController.representedObject = self
        }
    }
    

    This solved the issue for me. Hopefully there is enough info here to show up when others google this issue.