In my app I use two contexts: app delegate main context
and a private context.
The private context is set as follows:
var privateContext: NSManagedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
privateContext.persistentStoreCoordinator = context.persistentStoreCoordinator
I also set an observer on the private context to trigger a save via main context:
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyView.managedObjectContextDidSave(_:)), name: NSManagedObjectContextDidSaveNotification, object: self.privateContext)
I trigger a data download with a callback to the current ViewController. During the download, I process all objects in:
privateContext.performBlock {
// process objects
....
// now save
if self.privateContext.hasChanges {
privateDataManager.save()
}
}
The save in the private context, triggers the observer and this code gets invoked:
dispatch_async(AppUtils.GlobalMainQueue, {
self.context.mergeChangesFromContextDidSaveNotification(notification)
})
The problem is that every now and then, not all changes get persisted. Cannot say when or why - when I debug it it always works...
How do I know I have a problem? Well, I compare object count before and after the download. To add more 'colour':
Every download of data adds some new records. The app then selects which records are out-of-date and marks them for deletion (sets a flag on a record). It then saves them (new and 'to be deleted') in the private context. The 'save' triggers a 'merge into primary context' notification.
In theory, this notification triggers the 'merge' in a synchronous manner.
After the merge, assuming it does happen in-order, there is data reload - this reload only loads records that do not have the 'deleted' flag set.
The problem I am having is that the 'merge' does not seem to always happen before I reload (that's the only way I can explain this).
My question, assuming my analysis is correct, is how to force the merge to happen before the reload? Does the notification not happen in a synchronous manner?
I guess I could always save the private context and instead of triggering the notification, simply create a notification object using private context and force trigger the merge. But I would like to understand why the above code does not work as expected.
The main source on which I based my code can be found here.