1

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!

1

2 Answers 2

3

I believe your problem is the contents of the returnSource array. If that is a bunch of NSManagedObject instances 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:

  1. Create an array with the NSManagedObjectIDs of the NSManagedObject.
  2. Send the object ID array over thread boundry.
  3. Recreate an array with 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 NSManagedObjectContext instances that automatically registers for updates and cleanup when the current thread exits.

A normal use-case:

NSManagedObjectCotext* context = [NSManagedObjectCotext threadLocalContext]; // Do your stuff!! NSError* error = nil; if (![context saveWithFailureOption:NSManagedObjectContextCWSaveFailureOptionThreadDefault error:&error]) { // Handle error. } 

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.

Sign up to request clarification or add additional context in comments.

4 Comments

-1 While your code might be useful, it isn't really an answer to this specific problem.
Hey! Thanks i figured this one out myself and did exactly what you described here. :)
I have the same problem could you explain how get array of NSManagedObjectIDs please
re reset invalidation - 'It’s possible for all the objects in a managed object context to be invalidated simultaneously. (For example, as a result of calling reset, or if a store is removed from the the persistent store coordinator.) When this happens, NSFetchedResultsController does not invalidate all objects, nor does it send individual notifications for object deletions.' developer.apple.com/library/ios/#DOCUMENTATION/CoreData/…
1

There is no reason in this case to call reset on the background context because it will disappear anyway with the background thread and you never use it again in any case. You usually use reset with undo management when you want the context to forget previous steps.

Your major problem here is that your background thread is configured to receive notifications from the managed object context it creates. That is rather pointless.

Instead, you need to register the tableview controller (on the front thread) to receive the NSManagedObjectContextDidSaveNotification from the context on background thread. That way, when the background context saves, the front/main context will update itself with the new data which will trigger an update of the tableview.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.