Search code examples
swiftcocoacore-dataxcode6cocoa-bindings

Communicating with AppDelegate across scenes (Cocoa, swift)


In Xcode 6 (7 too), I'm looking to find out how to get managedObjectContext and use it in a ViewController in a different scene.

  1. I started a new Cocoa project, clicked 'Use CoreData'
  2. Added an entity in CoreData, generated a managedObject for it
  3. Added an array controller, and bound it to the entity
  4. I want to bind the array controller to the managedObjectContext, but I also want to bind the tableView (in my view controller) to the array controller. They are in different scenes, which seems to mean different namespaces.

What I've tried to do: Set an instance variable in ViewController:

var managedObjectContext: NSManagedObjectContext!

In viewDidAppear() I added:

if let app = NSApplication.sharedApplication().delegate! as? AppDelegate {
    if let context = app.managedObjectContext{
        managedObjectContext = context
    } else {
        print("There was no context available, didn't work")
    }
}

Then I bound the columns of the table to the properties of the entity. And cocoa bindings autocompleted, meaning the context was at least recognized properly.

However when I run it, it fails silently with: 'Cannot perform operation without a managed object context'. When debugging the context is being set as a real object, but I have no idea if it's actually initialized. I looked through the docs and cocoa binding troubleshooting but this seems to be a coredata issue.

(I've looked here: Getting managedObjectContext from AppDelegate but I can't override the normal init in swift)


Solution

  • I made one example for you. I have one Entity, called Person with 2 attributes, name and age. This is my ViewController:

    import Cocoa
    
    class ViewController: NSViewController {
    
        // ManagedObjectContext from AppDelegate
        lazy var moc: NSManagedObjectContext = {
            let appDel = NSApplication.sharedApplication().delegate as! AppDelegate
            return appDel.managedObjectContext
        }()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Populate some sample data
            let firstPerson = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: moc) as! Person
            firstPerson.name = "Jesse Pinkman"
            firstPerson.age = 25
    
        }
    }
    

    And in IB i have one table view and one array controller. Set array controller's entity to Person:

    And the bound your array controller's managed object context to your viewcontroller's managed object context, in my example self.moc: enter image description here

    And then just bound your table view's colum's to your array controller.