I have an application using Core Data with the following, fairly standard, managed object context hierarchy:
Persistent Store Coordinator ↳ Save Context (Private Queue Concurrency Type) ↳ Main Context (Main Queue Concurrency Type) ↳ Private Context (Private Queue Concurrency Type)
The merge policy for all managed object contexts is set to NSMergeByPropertyObjectTrumpMergePolicy
I am observing NSManagedObjectContextDidSaveNotification
which will invoke the following function when the Private Context is saved and merge changes to the Main Context:
func contextDidSaveNotificationHandler(notification: NSNotification) { if let savedContext = notification.object as? NSManagedObjectContext { if savedContext == privateObjectContext { mainObjectContext.performBlock({ if let updatedObjects = notification.userInfo![NSUpdatedObjectsKey] as? Set<NSManagedObject> { // // fire faults on the updated objects // for obj in updatedObjects { mainObjectContext.objectWithID(obj.objectID).willAccessValueForKey(nil) } } mainObjectContext.mergeChangesFromContextDidSaveNotification(notification) }) } } }
This is working most of the time but sometimes I am finding that changes to existing objects in the Private Context are not being merged into the Main Context. I can't figure out why -- the private context save is successful; the NSManagedObjectContextDidSaveNotification
notification is being sent; the notification handler is being invoked; notification.userInfo?[NSUpdatedObjectsKey]
contains the correctly updated objects; but at the end, the main context is not synchronized with the private context. (ie: the managed objects in the main context are not in sync with the values contained in notification.userInfo?[NSUpdatedObjectsKey]
) If I kill the app and relaunch it, the contexts become synchronized again (after loading objects from the persistent store).
I have -com.apple.CoreData.ConcurrencyDebug 1
enabled in my launch arguments, and all Core Data multithreading rules are being followed. I can't see anything overtly wrong with my managed object context hierarchy or the merging function. What could possibly be causing this?
3 Answers
Answers 1
You can't merge sibling context. You have to merge from the parent down. In other words change
if savedContext == privateObjectContext {
to
if savedContext == savingObjectContext {
where the savingObjectContext
is the parent context of the main context.
Answers 2
You could always set your mainQueueContext as your privateQueueContext's parent:
privateObjectContext.parent = mainObjectContext
This will merge your saves into your main object context. I used this in a project where I parse JSON, and set core data objects in a privateQueue's perform block, with my mainContext set as the parent. Then I simple save the private, and then access the data from the main thread/main context. Works like a charm. I should add I do not keep the private context in memory, it is created new when I need it.
Answers 3
The problem is with your merge policy. Try changing to to NSErrorMergePolicy and I think you will start to see merge conflicts. At the least this will give you more of an idea of the underlying cause
0 comments:
Post a Comment