I recently managed to catch an extremely rare exception in my code and was hoping folks here could help me understand it. I have a game which is tracking elapsed time and persisting the value to Core Data every second. At the same time a user could be playing the game and causing the score to update, which is also saved in Core Data. I suspect that I should be serializing saves, but at the moment I'm not. Everything works great 99.99% of the time, but once in a while the call to context.save()
throws an exception.
I have a merge policy set as so:
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
And here's how I save elapsed time. The same pattern is used for updating a player's score.
func saveElapsedTime() {
let container = (UIApplication.shared.delegate as! AppDelegate).persistentContainer
container.performBackgroundTask() { (context) in
let storedGame = context.object(with: self.storedGameID) as! StoredGame
storedGame.elapsedTime = Int32(self.elapsedTime)
do {
try context.save()
} catch let nserror as NSError {
print("saveElapsedTime: failed to save: \(nserror). userInfo: \(nserror.userInfo).")
}
}
}
The rare error I was able to catch looks like this:
Error Domain=NSCocoaErrorDomain Code=133020 "Could not resolve merge changes."
<snip>...with oldVersion = 463 and newVersion = 463...<snip>
I've seen plenty of posts where the old and new versions are off by one or a small number, and people recommend setting a merge policy which is different than the default. I'm guessing that in my case where oldVersion == newVersion it's because multiple threads are trying to save at the exact same time. Can someone confirm this just by looking at the error message? Should I be serializing all saves using an OperationQueue like in this example: NSPersistentContainer concurrency for saving to core data?
Thanks in advance.