0

So this is pretty hard to debug. First, that's the basic setup:

I have a method that runs every second:

@objc private func trigger() {
    appDelegate.persistentContainer.performBackgroundTask { (privateContext) in

        /* modifying database */

        do {
            // I tried setting a mergePolicy, but it didn't help
            privateContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
            try privateContext.save()
        } catch let error as NSError {
            fatalError("Couldn't save private context in Handler: \(error.debugDescription)")
        }
    }    
}

As you see, it's using a private context.

In my appDelegate (where I have the main context) I set this up:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        /* more stuff */

        NotificationCenter.default.addObserver(self, selector: #selector(mergeToMainViewContext(notification:)), name: NSNotification.Name.NSManagedObjectContextDidSave, object: nil)

        return true
}

func saveContext () {
    let context = persistentContainer.viewContext
    context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy // That's what I added to try. Nothing changed though
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}

func mergeToMainViewContext(notification: Notification) {
    persistentContainer.viewContext.mergeChanges(fromContextDidSave: notification)
}

You see, I added an observer that should fire every time the private context (or any other context) saves.

However, occasionally the app crashes. Most of the time, it crashes without any error messages. Xcode just tells me that it crashes at this line:

persistentContainer.viewContext.mergeChanges(fromContextDidSave: notification)

And that's it :/.

Sometimes though, it crashes and says that there has been a merge conflict. The differences that are listed there are tiny. There are value differences of 0.1 or something. That's why I tried using mergePolicy but it doesn't help.

(I would post this error message, but I don't know how to reproduce this bug)

I have no idea where to look, how to start debugging this. Does anyone have an idea?

Let me know, if you need any more information! Thanks for any help

SwiftedMind
  • 3,701
  • 3
  • 29
  • 63
  • 1
    see my answer here: http://stackoverflow.com/questions/42733574/nspersistentcontainer-concurrency-for-saving-to-core-data/42745378. short answer don't write in the `viewContext` – Jon Rose Mar 14 '17 at 09:27
  • Thanks. But I don't quite understand how I can use the `viewContext` for reading. If I save the `private viewContext` in `performBackgroundTask` how does the main `viewContext` know about the changes, if I don't merge (=write) them into it? – SwiftedMind Mar 14 '17 at 09:33
  • 1
    self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true – Jon Rose Mar 14 '17 at 09:37
  • Yeah, I saw that in your answer. But isn't `parent` referring to a `parent viewContext`? Why is the `private viewContext` a parent of the main `viewContext`? Or am I misunderstanding something? – SwiftedMind Mar 14 '17 at 09:39
  • 1
    The parent of the `viewContext` is the storeCoordinator which is also the parent of the private temporary writing contexts. The private context saves up to the store and the viewContext merges the changes back down. – Jon Rose Mar 14 '17 at 09:44
  • Ah okay. Thanks, that's actually interesting to know (Apple has no documentation for this property, unfortunately) – SwiftedMind Mar 14 '17 at 09:45

0 Answers0