Mac OSX - Core data isn't stored

2019-09-06 18:51发布

问题:

In my app I use two table views that are bound to each their NSArrayController and the array controllers are set to use Core Data entities. When data is generated, an NSObject is created and values are stored in it with obj.setValue(_:forKey:). After this the object is simply added to the array controller with ac.addObject().

Shouldn't this suffice to have Core Data taking care of persistent storage of the data?

In any case, if I try to save the data by calling saveAction() it tells me that the MOC has no changes (moc.hasChanges = false) so it doesn't even begin to save the data with this method.

What else do I need to take care of to make Core Data store the data properly and acknowledge changes?

The array controllers are set in Interface Builder as follows:

  • Mode: Entity Name
  • Entity Name: 'name of entity in data model'
  • Prepares Content is checked

They are also correctly bound to the managed object context.

Simplified, relevant code from my app:

    /* Clear existing data. */
    let range:NSRange = NSMakeRange(0, arrayController.arrangedObjects.count);
    let indexSet:NSIndexSet = NSIndexSet(indexesInRange: range);
    arrayController.removeObjectsAtArrangedObjectIndexes(indexSet);

    let array = generateData();

    /* Generate data. */
    for i in 0 ..< array.count
    {
        let data = array[i];

        /* Create new data object. */
        var obj:NSObject = arrayController.newObject() as! NSObject;
        obj.setValue(data.name, forKey: "name");
        obj.setValue(data.type, forKey: "type");
        obj.setValue(data.category, forKey: "category");

        /* Add it to the array controller's contentArray. */
        arrayController.addObject(obj);
    }

UPDATE:

It looks like my app is instantiating four MOCs when it launches. I suspect that the way how I add them in the Storyboard for the two array controllers is wrong. I added an NSObject to the two table view controllers (which also contain their array controllers) and set their base classes to be my CoreDataDelegate (which is my class for the core data code that is normally in AppDelegate). I suspect this is where the multiple instances of CoreDataDelegate are created. The question is: How should I do this right so that the array controllers can reach my CoreDataDelegate class?

回答1:

I made my core data delegate class a Singleton which solved the problem for me...

class CoreDataDelegate : NSObject
{
    static let instance = CoreDataDelegate();
    ...
}

Then I have a reference to it in my AppDelegate (which is also a singleton) ...

@NSApplicationMain
class AppDelegate : NSObject, NSApplicationDelegate
{
    static let instance = AppDelegate();
    let coreData:CoreDataDelegate;

    override init()
    {
        coreData = CoreDataDelegate.instance;
        super.init();
    }

    ...
}

Then in the storyboard I added an NSObject to my two table view controllers and set the base class to AppDelegate. And then bound the ArrayControllers to the moc via AppDelegate/coreData.moc.

Now only one instance of CoreDataDelegate is created (and therefore only one moc) and I can happily report that saving works now!