ericg
ericg

Reputation: 8722

Making Managed Object Context available to array controller in Storyboard scene

I have a core data, document based, storyboard OS X application.

There is a test project here:

https://github.com/ericgorr/sb_ac_doc

which is just the default project Xcode creates with a few modifications.

I have a single view controller and the view contains a table view which will eventually display the data in the Core Data document. I will also using an array controller to manage the rows for the table view.

The three scenes are:

The Main View Controller Scene contains the TestItem Array Controller.

The TestItem View Controller contains the code:

class ViewController: NSViewController
{
    var context: NSManagedObjectContext?

    //
    // ...
    //    
}

The TestItem Array Controller contains the Parameters Binding:

Managed Object Context
    Bind to: Main View Controller
    Model Key Path: context

In Document.swift:

override func makeWindowControllers()
{
    let moc = self.managedObjectContext!

    // Returns the Storyboard that contains your Document window.
    let storyboard          = NSStoryboard(name: "Main", bundle: nil)
    let windowController    = storyboard.instantiateControllerWithIdentifier( "Document Window Controller" ) as! NSWindowController
    let contentController   = windowController.contentViewController as! ViewController

    NSLog( "%@", self.managedObjectContext! )

    contentController.context = self.managedObjectContext!

    NSLog( "%@", contentController.context! )

    self.addWindowController( windowController )
}

This is my attempt to pass the MOC to the view controller before the array controller attempts to access it.

The NSLog's both print out valid values.

However, I am getting the following crash:

2016-03-13 20:13:02.667 sb_ac_doc[73021:16415257] Cannot perform operation without a managed object context
2016-03-13 20:13:02.669 sb_ac_doc[73021:16415257] (
    0   CoreFoundation                      0x00007fff956f9ae2 __exceptionPreprocess + 178
    1   libobjc.A.dylib                     0x00007fff9a09073c objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff956f998d +[NSException raise:format:] + 205
    3   AppKit                              0x00007fff8c8224e7 -[_NSManagedProxy _managedObjectContext] + 66
    4   AppKit                              0x00007fff8c822507 -[_NSManagedProxy _persistentStoreCoordinator] + 22
    5   AppKit                              0x00007fff8c82257a -[_NSManagedProxy _entity] + 46
    6   AppKit                              0x00007fff8c822802 -[_NSManagedProxy fetchRequestWithSortDescriptors:limit:] + 89
    7   AppKit                              0x00007fff8c821fec -[NSObjectController(NSManagedController) _executeFetch:didCommitSuccessfully:actionSender:] + 75
    8   AppKit                              0x00007fff8c5c18c2 -[NSController _controllerEditor:didCommit:contextInfo:] + 185
    9   CoreFoundation                      0x00007fff955c417c __invoking___ + 140
    10  CoreFoundation                      0x00007fff955c3fce -[NSInvocation invoke] + 286
    11  CoreFoundation                      0x00007fff95663be6 -[NSInvocation invokeWithTarget:] + 54
    12  Foundation                          0x00007fff87cce345 __NSFireDelayedPerform + 377
    13  CoreFoundation                      0x00007fff9563fbc4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    14  CoreFoundation                      0x00007fff9563f853 __CFRunLoopDoTimer + 1075
    15  CoreFoundation                      0x00007fff956bde6a __CFRunLoopDoTimers + 298
    16  CoreFoundation                      0x00007fff955facd1 __CFRunLoopRun + 1841
    17  CoreFoundation                      0x00007fff955fa338 CFRunLoopRunSpecific + 296
    18  HIToolbox                           0x00007fff8add1935 RunCurrentEventLoopInMode + 235
    19  HIToolbox                           0x00007fff8add1677 ReceiveNextEventCommon + 184
    20  HIToolbox                           0x00007fff8add15af _BlockUntilNextEventMatchingListInModeWithFilter + 71
    21  AppKit                              0x00007fff8c25e0ee _DPSNextEvent + 1067
    22  AppKit                              0x00007fff8c62a943 -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 454
    23  AppKit                              0x00007fff8c253fc8 -[NSApplication run] + 682
    24  AppKit                              0x00007fff8c1d6520 NSApplicationMain + 1176
    25  sb_ac_doc                           0x0000000100002427 main + 87
    26  libdyld.dylib                       0x00007fff987455ad start + 1
)

What is the correct pattern I should use so the array controller can access the MOC of the document?

Upvotes: 1

Views: 680

Answers (2)

Willeke
Willeke

Reputation: 15598

If you use bindings, you have to modify properties in a KVO compliant way. Put dynamic in front of var context: NSManagedObjectContext?.

Upvotes: 2

Allen
Allen

Reputation: 1734

I think the property context of ViewController is missing. Let's assume we have a Core Data Stack. Usually it can be generated automatically once you check Use Core Data option when creating a new project.

enter image description here

And then implementing the managedObjectContext which is created in AppDelegate for the context of ViewController:

var context: NSManagedObjectContext? {
    guard let appDelegate = NSApplication.sharedApplication().delegate as? AppDelegate else {
        return nil
    }
    return appDelegate.managedObjectContext
}

As to other minor modification, I created a pull request via GitHub. Please take it for a reference.

Upvotes: -1

Related Questions