views:

87

answers:

2

I need to create NSManagedObject instances, do some stuff with them and then trash them or store to sqlite db. The problem is, I cannot create instances of NSManagedObject unconnected to MSManagedObjectContext and this means I have to clear up somehow after I decide that I don't need some of the objects in my db.

To deal with it, I have created an in-memory store using the same coordinator and I'm placing temporary objects there by using assignObject:toPersistentStore. Now, how do I ensure that these temporary objects don't get to the data, which I fetch from the common to both stores context? Or do I have to create separate contexts for such a task?


UPD:

Now I'm thinking about making separate context for in-memory store. How do I move objects from one context to another? Just using [context insertObject:]? Will it work OK in this setup? If I insert one object from the graph of objects, does the whole graph also get inserted into context?

A: 

The correct way to achieve this sort of thing is with a new managed object context. You create a managed object context with the same persistent store:

NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease];
[tempContext setPersistentStore:[originalContext persistentStore]];

Then you add new objects, mutate them, etc.

When it comes time to save, you need to call [tempContext save:...] on the tempContext, and handle the save notification to merge that into your original context. To discard the objects, just release this temporary context and forget about it.

So when you save the temporary context, the changes are persisted to the store, and you just need to get those changes back into your main context:

/* Called when the temp context is saved */
- (void)tempContextSaved:(NSNotification *)notification {
    /* Merge the changes into the original managed object context */
    [originalContext mergeChangesFromContextDidSaveNotification:notification];
}

// Here's where we do the save itself

// Add the notification handler
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(tempContextSaved:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:tempContext];

// Save
[tempContext save:NULL];
// Remove the handler again
[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:NSManagedObjectContextDidSaveNotification
                                              object:tempContext];

This is also the way you should handle multi-threaded core data operations. One context per thread.

If you need to access existing objects from this temporary context (to add relations etc.) then you need to use the object's ID to get a new instance like this:

NSManagedObject *objectInOriginalContext = ...;
NSManagedObject *objectInTemporaryContext = [tempContext objectWithID:[objectInOriginalContext objectID]];

If you try to use an NSManagedObject in the wrong context you will get exceptions while saving.

Mike Weller
Creating a second context just for this is very wasteful as standing up a `NSManagedObjectContext` is expensive in both memory and CPU. I realize this was originally in some of the Apple examples, but they have updated and corrected those examples.
Marcus S. Zarra
+2  A: 

The easiest way to do this is to create your NSManagedObject instances without an associated NSManagedObjectContext.

NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC];
NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity inManagedObjectContext:nil];

Then when you want to save it:

[myMOC insertObject:unassociatedObjet];
NSError *error = nil;
[myMoc save:&error];
//Check the error!
Marcus S. Zarra
If unassociatedObject has refs to other unassociated objects, should I insert them one by one or myMOC is smart enough to collect all refs and insert them also?
fspirit
It is smart enough to handle the relationships as well.
Marcus S. Zarra
I've found that in my situation it's enough to delete unwanted objects from the context, when needed, cause there are much more objects from the initial scope that will be persisted. If I meet the inverse situation, I'll go with your solution.
fspirit