As the title suggests im working with a Core Data Application which gets filled with objects in different background threads (XML Parsing)
In my background thread I’m doing this
managedContext = [[NSManagedObjectContext alloc] init];
[managedContext setUndoManager:nil];
[managedContext setPersistentStoreCoordinator: [[DataManager sharedManager] persistentStoreCoordinator]];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:@selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:managedContext];
NSMutableArray *returnSource = [[self parseDocument:doc] retain];
[managedContext save:&error];
if (error) {
NSLog(@"saving error in datafeed");
}
[managedContext reset];
[self performSelectorOnMainThread:@selector(parseCompleteWithSource:) withObject:returnSource waitUntilDone:YES];
The Merge method looks like this:
NSManagedObjectContext *mainContext = [[DataManager sharedManager] managedObjectContext];
// Merge changes into the main context on the main thread
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:YES];
[[NSNotificationCenter defaultCenter] removeObserver:self];
I think the merge is successful but as i want to display it in an UITableView it always tells me that my objects are invalidated which is to be expected because of
[managedContext reset];
What i want to do is show the Items which are currently in the database, in the background parse the xml and if thats finished i want to update the UITableView with the new / updated objects. How would I do that, can i “update” the objects to the other Context somehow or is the merge not working correctly?
Do I need to define something specific in the Main ObjectContext?
I’ve tried different mergepolicies without any luck.
Hope you can help me, thanks!
I believe your problem is the contents of the
returnSourcearray. If that is a bunch ofNSManagedObjectinstances then they will have been created on the background thread by the background thread context.You call to
-[NSManagedObjectContext reset]will invalidate them, since that is what you explicitly tell the context to do. But that is not the big problem.You then go on to send the array to a the main thread, passing
NSManagedObjectinstances over thread borders, and between contexts is a big no-no.What you need to do is:
NSManagedObjectIDs of theNSManagedObject.NSManagedObjects from the managed object IDs on the new thread with it’s context.I have made some Core Data helpers, following the rule of three (the third time you write something, make it general).
Most importantly I have hidden the complexity of managing different managed object contexts for each thread, handling notifications, and all that junk. Instead I have introduced the concept of thread local contexts. Basically lazily created
NSManagedObjectContextinstances that automatically registers for updates and cleanup when the current thread exits.A normal use-case:
The full source code, including a sample app for parsing the news RSS from apple.com and store it in Core Data, is available here: https://github.com/jayway/CWCoreData.