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.
Using the default Xcode generated project and including CoreData puts the managedObjectContext
member on the AppDelegate
. You can add the following code to your ViewController, then use managedObjectContext
as the "Model Key Path" with binding to ViewController
for your NSArrayController
.
lazy var managedObjectContext: NSManagedObjectContext = {
return (NSApplication.sharedApplication().delegate
as? AppDelegate)?.managedObjectContext }()!
This simply creates a member which redirects to where your actual MOC is stored. This is useful because the NSArrayController binding happens before viewDidLoad()
, hence why an instance member will not suffice. Also, if you want to refactor to a singleton CoreDataManager
class, you can just change where to redirect to. Additionally, you could add this as a class extension to enable all ViewControllers
to access your MOC.
Objective-C version upon request:
@interface MyViewController ()
@property (nonatomic, readonly) NSMangedObjectContext* managedObjectContext;
@end
@implementation MyViewController
- (NSManagedObjectContext*)managedObjectContext
{
return ((AppDelegate*)([NSApplication sharedApplication].delegate)).managedObjectContext;
}
...
@end
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.
You have always been able to bind through NSApplication with a keypath of delegate.managedObjectContext if the application delegate owns the core data stack. Otherwise you could pass pass the MOC through to each view controller with a MOC property on each one, which is strongly preferred by those who argue that the app delegate shouldn't be used to own singleton MOCs, and that there's further utility in being able to provide each VC a separate MOC.
I believe you could also create a MOC instance in the storyboard in IB. There's also always been a MOC object for nibs, at least. Though I haven't used that enough to know how it relates to a programmatic core data stacks. Probably better to just have a MOC property somewhere you can access in either the VC hierarchy or app delegate
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With