Search code examples
ioscore-datansmanagedobjectnsmanagedobjectcontexttemporary

CoreData: Create temporary models and maybe save to context


I have a problem with Core Data, because I don't know the best way to handle my problem:

I load a json from a server and parse the results in ManagedObjects. At first the ManagedObjects should be temporary. But the user can put a ManagedObject to a leaflet. And then the ManagedObject should be saved to CoreData. (The object should be accessible offline) When the user load the same objects some time later from the server, already saved ManagedObjects should be fetched.

So I don't want to put every object in CoreData / PersistantStore the user doesn't need.

First what I do is to create a background context:

__block NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
backgroundContext.parentContext = context;

With a fetch I check if there is already a ManagedObject in the persistantstore. If there is one, I will take this. else create a new ManagedObject in nil context.

NSArray *results = [backgroundContext executeFetchRequest:fetch error:&error];

if (!error && results.count == 1) {
    myModel = [results objectAtIndex:0];
}
else {
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyModel" inManagedObjectContext:backgroundContext];
    myModel = (MyModel *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
}

And I do the same with every relationship:

if (! myModel.relation) {
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Relation" inManagedObjectContext:backgroundContext];
    myModel.relation = (Relation *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:myModel.managedObjectContext];
}

Works fine so far with creating the models. But how to save one model?

The managedObjectContext is nil. If I call save: on the managedObjectContext, it saves everything.

In my AppDelegate i wrote a function to insert a ManagedObject in the main ManagedObjectContext:

- (void)insertObjectAndSave:(NSManagedObject *)managedObject {
    if (!managedObject.managedObjectContext) {
        [self.managedObjectContext insertObject:managedObject];
    }

    [self saveContext];
}

Is this a good solution? or is there a better way to save temporary ManagedObjects in the main ManagedObjectContext?


Solution

  • You could not create the objects with nil context but with a "temp" context. If you want to save them, call [tempContext save:nil];. If you want to discard them, just throw away the context.

    Another strategy is to avoid the complexity of multiple context altogether by adding a simple boolean attribute temp to your entity (if relationships are one-to-many, only the top level entity needs to have this). You can save by default and display only non-temp items. You can delete temp items, including all related items, immediately or periodically.