1

Searched entire Internet but couldn’t find the modern solution for my problem. I want to use NSObjectController in pair with Core Data through Cocoa Bindings and struggle to set it up properly. Worth noting that I’m using latest version of Xcode and Swift.

What I’ve done:

For testing purposes I’ve done the following:

  1. Created an macOS app with “Use Core Data” option selected (the app is not document based);
  2. Dragged 2 NSTextFields into the Storyboard Dragged NSObjectController to the view controller scene;
  3. Added Employee Entity to Core Data model with 2 attributes “name” and “surname”;
  4. Done everything from the answer in How do I bind my Array Controller to my core data model?
  5. Set NSObjectController to entity mode and typed in “Employee”,
  6. Prepares Content selected, Use Lazy Fetching selected so all three options checked;
  7. Binded the NSObjectController’s Managed Object Context in bindings inspector to the View Controller’s managedObjectContext;
  8. Binded NSTextFields as follows: Value - Object Controller, Controller key - selection, Model Key Path - name (for 1st text field) and surname (for 2nd).

That’s it.

First set of questions: What I did wrong and how to fix it if it’s not completely wrong approach?

I’ve read in some post on stackoverflow that doing it that way allows automatic saving and fetching from Core Data model. That’s why I assumed it should work.

So here is a Second set of questions: Is it true? If it is then why text fields are not filled when view is displayed? If it is not then how to achieve it if possible (trying to write as less code as possible)?

Third question: If I used approach that is completely wrong would someone help me to connect Core Data and NSObjectController using Cocoa bindings and show me the way of doing so with as less code written as possible using the right approach?

Taking into account that there no fresh posts about this topic in the wilds I think the right answer could help a lot of people that are developing a macOS app.

Thanks in advance!

  • What results did you get, and how did they differ from what you intended? – Charles Srstka Jun 20 '18 at 05:15
  • Textfileds didn’t fill up with data I entered. I assumed that data for these fields would automatically saved when I quit from the app and fetched from data model upon view controller loading and presented in text fields. – Gregory Kovler Jun 20 '18 at 05:19
  • 1
    You did not mention anything about inserting a Employee object. I mean, when you launch this app for the first time, the object graph (in the user's store) is empty and your text fields will probably indicate "No selection". You need some code to execute a fetch for an Employee object and, if none is found (as will happen upon first launch) to insert one. You may put such code in `applicationDidFinishLaunching`. – Jerry Krinock Jun 20 '18 at 06:13
  • Text fields indeed show no selection! Do I need to create NSManagedObject subclass from entity for this or there is another solution? And what code it should be in applicationDidFinishLaunching for inserting an object? I suppose my initial approach is semi-right? Right? – Gregory Kovler Jun 20 '18 at 06:21
  • Can you post a link to the "post on stackoverflow that doing it that way"? – Willeke Jun 20 '18 at 10:32
  • https://stackoverflow.com/questions/16883967/how-to-use-nsobjectcontroller-with-core-data – Gregory Kovler Jun 20 '18 at 11:43
  • Author of question asked for automatic fetching and saving and accepted the answer. Little has changed in terms of bindings and Object controller, so I thought it was a right way for automatic fetching and saving. Hope it’s the right approach. But if not I would appreciate a help in that direction. – Gregory Kovler Jun 20 '18 at 11:46

1 Answers1

1

I think your basic approach is correct, although it is important to understand that you need a real object, an instance, in order for it to work.

Creating a NSManagedObject subclass is generally desirable, and is almost always done in a real project, so you can define and use properties. You can do it easily nowadays by selecting the data model in Xcode's Project Navigator and clicking in the menu: Editor > Create NSManagedObject Subclass…. Technically it is not necessary, and in a demo or proof-of-concept, you often muddle through with NSManagedObject.

Assuming you are using the Xcode project template as you described, wherein AppDelegate has a property managedObjectContext, the following function in your AppDelegate class will maintain, creating when necessary, and return, what I call a singular object – an object of a particular entity, in this case Employee, which your app requires there to be one and only one of in the store.

@discardableResult func singularEmployee() -> NSManagedObject? {
    var singularEmployee: NSManagedObject? = nil
    let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest(entityName: "Employee")
    let objects = try? self.managedObjectContext.fetch(fetchRequest)
    singularEmployee = objects?.first

    if singularEmployee == nil {
        singularEmployee = NSEntityDescription.insertNewObject(forEntityName: "Employee", into: self.managedObjectContext)
    }
    return singularEmployee
}

Then, add this line of code to applicationDidFinishLaunching

    singularEmployee()
Jerry Krinock
  • 4,860
  • 33
  • 39
  • Thanks Jerry! You simplified creation of the first real object for entity! So the only thing left is to add @objc let managedObjectContext to view controller, bind it to NSObjectControlller and bind those text fields to Object controller (entity attributes). Meanwhile, I’ve read Marcus Zarra‘s book about core data and learned, that using NSObjectController and Core Data together automatically retrieves data from core data model, removes and updates values but in order to save managedObjectContext you need explicitly call for managedObjectContext.save(). So no automatic saving, unfortunately. – Gregory Kovler Jun 25 '18 at 19:31
  • I think Apple considers *no automatic saving* to be a feature, not a bug. The managed object context is thought of as your "scratchpad". There are many functions where it may be appropriate to save() it. Here are four: (1) the text fields' endEditing(), (2) the superview's viewWillMove(toWindow:) when the parameter is nil, (3) the window's windowWillClose(), (4) NSApp's applicationWillTerminate(). – Jerry Krinock Jun 26 '18 at 07:47