Search code examples
ioscore-dataxcode8core-data-migration

Xcode8 and Core Data automatic lightweight migration


I've been trying to perform a lightweight migration for my Core Data schema using Xcode8, and running into some strange problem. The first time I load the store after the update, with both the NSMigratePersistentStoresAutomaticallyOption and NSInferMappingModelAutomaticallyOption flags set to YES in the options dictionary, I run into this error:

2016-10-01 09:59:17.307862 CJournal[1162:549816] loadLocalStoreIntoPSC using store = file:///private/var/mobile/Containers/Shared/AppGroup/04521C25-2FE6-4CFD-ACB5-70550B63499E/ContactsJournal.sqlite
2016-10-01 09:59:18.373568 CJournal[1162:549816] [error] error: Failed to delete support directory for store: /private/var/mobile/Containers/Shared/AppGroup/04521C25-2FE6-4CFD-ACB5-70550B63499E/.ContactsJournal.sqlite.migrationdestination_41b5a6b5c6e848c462a8480cd24caef3
2016-10-01 09:59:18.656164 CJournal[1162:549816] [error] error: CoreData: error: (migration) migration failed with error (null)
2016-10-01 09:59:18.664001 CJournal[1162:549816] [error] error: -addPersistentStoreWithType:SQLite configuration:(null) URL:file:///private/var/mobile/Containers/Shared/AppGroup/04521C25-2FE6-4CFD-ACB5-70550B63499E/ContactsJournal.sqlite options:{
    NSInferMappingModelAutomaticallyOption = 1;
    NSMigratePersistentStoresAutomaticallyOption = 1;
} ... returned error Error Domain=NSSQLiteErrorDomain Code=8 "(null)" UserInfo={NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/04521C25-2FE6-4CFD-ACB5-70550B63499E/ContactsJournal.sqlite, Source database Path=/private/var/mobile/Containers/Shared/AppGroup/04521C25-2FE6-4CFD-ACB5-70550B63499E/.ContactsJournal.sqlite.migrationdestination_41b5a6b5c6e848c462a8480cd24caef3, reason=Failed to replace destination database} with userInfo dictionary {
    NSFilePath = "/private/var/mobile/Containers/Shared/AppGroup/04521C25-2FE6-4CFD-ACB5-70550B63499E/ContactsJournal.sqlite";
    "Source database Path" = "/private/var/mobile/Containers/Shared/AppGroup/04521C25-2FE6-4CFD-ACB5-70550B63499E/.ContactsJournal.sqlite.migrationdestination_41b5a6b5c6e848c462a8480cd24caef3";
    reason = "Failed to replace destination database";
}

This is happening on both iOS10 simulator and iOS10 device. The strange thing is that the 2nd run I run the app and it attempts the migration, it runs fine, without any errors!

This is the code I use to add the store:

NSMutableDictionary *options = [NSMutableDictionary dictionaryWithObjectsAndKeys:@YES, NSMigratePersistentStoresAutomaticallyOption, @YES, NSInferMappingModelAutomaticallyOption, nil];

NSPersistentStore *newStore = [self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:localStoreURL options:options error:&error];

I've also tried using the -com.apple.CoreData.MigrationDebug 1 flag in "Arguments Passed on Launch" but it doesn't produce any output that might be helpful.

Any idea what might be going wrong, or how to debug if the migration is failing due to some validation issues?


Solution

  • I figured out the problem ... before the lightweight migration, I was doing a backup of the existing database, and so I was creating a NSPersistentStoreCoordinator (separate from the usual stack) and adding the persistentStore to it without any lightweight migration options. This apparently puts a lock on the store file which was preventing the migration on the main Core Data stack's persistentStoreCoordinator, even after the backup process was done. The fix was to remove the persistentStore from the backup persistentStoreCoordinator. This makes sure the migration works fine and addPersistentStoreWithType doesn't throw an error at this point.