0

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.

Community
  • 1
  • 1
zevij
  • 2,416
  • 1
  • 23
  • 32
  • Tell me, please, it's "not all changes get persisted", or "not all changes appears in main context"? – bteapot Sep 22 '16 at 12:41
  • the latter..."not all changes appears in main context" – zevij Sep 22 '16 at 12:44
  • It's normal behaviour of a merge operation: it updates only objects that already exists in receiver context. So, if you want your FRC to notice objects that have been inserted into persistent store by background context – merge changes into main context and refetch. – bteapot Sep 22 '16 at 12:49
  • But I already merge - Look at the dispatch_async above. It gets triggered via the notification. Then runs in the main queue, stopping background thread. After the merge there is data reload. Unless every now there's a race condition between the merge and load that is due to the notification not triggering the save immediately...which is the only thing I can think of. Cannot 'capture' it in the debugger as the merge always seem to 'behave' – zevij Sep 22 '16 at 12:54
  • "stopping background thread" is not correct in the case of `dispatch_async`. Use `dispatch_sync` for that effect. – bteapot Sep 22 '16 at 13:22
  • Let me rephrase: I agree with you. See code above. I am not 'stopping' anything, just using main queue to merge. The only thing I can think of is that the notification triggers the merge (every now and then) after reload. But am I using Apple's paradigm. I have not tried anything out of the ordinary - https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/ChangeManagement.html – zevij Sep 22 '16 at 13:30
  • Hm, it should work. Can you describe in detail what appears to be wrong? No specific objects in tables? Incorrect aggregate results? – bteapot Sep 22 '16 at 13:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/123958/discussion-between-goggelj-and-bteapot). – zevij Sep 22 '16 at 14:01

0 Answers0