Preventing a CoreData crash for upgrading users
If your app is crashing in the Simulator when upgrading, your users will have crashes too.
To avoid this, you need to make sure you follow these steps:
- Make sure you do NOT change the original version of your data model in any way.
- In Xcode, select your xcdatamodel file, then from the menu choose Editor > Add Model Version...
- Xcode will suggest a new version name, based on the current model. Make a mental note of the new version name, then click Finish.
- Select the xcdatamodel file again, go to File inspector and under Model Version, select the new version name to make this your current version.
- In Project Navigator, select the new version of the xcdatamodel. Add your attribute.
It's important to follow these steps in this order. If you add your attribute before creating the new model or making it your current version, you will have crashes.
EDIT: This will only work if you enable lightweight migrations. This is a code snippet of how to do this:
let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
do {
//coordinator is an NSPersistentStoreCoordinator
try coordinator!.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options
} catch var error as NSError {
// handle error however you want here...
abort()
}
Update iOS Core Data Version to Avoid a Crash
If you are using any version control system, you can retrieve the old model and do it the right way, follow this documentation to do so.
In order to stop the users app from crashing, you can erase the old sqlite file and generate a new one using the updated model.
You can do something similar to this code. Notice that this will erase the sqlite file every time your app is not able to open it
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
{
if(error)
{
//Erase old sqlite
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
//Make new persistent store for future saves
if (![self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
// do something with the error
}
}
}
Crash on change to Core Data after migration
You can't keep changing the same model version and expect Core Data to keep up. The migration options you're using only apply when the data doesn't match the current model version but does match some older version included in your app. With automatic lightweight migration, Core Data figures out how to update your persistent store to use the new model. If you change the same version of the model, you may prevent Core Data from matching the persistent store file to any model version, and then you get this exception.
You mention that you made some changes and it worked. Not every change affects the version hash for the model. A Core Data model is uniquely identified by the version hashes of its entities as returned by the [NSEntityDescription versionHash]
. That in turn depends on the result of the value of versionHash
on NSRelationshipDescription
, NSAttributeDescription
, and NSPropertyDescription
. Some minor changes don't affect any version hashes. In general changes don't affect the version hash unless they affect the formatting of data in the underlying SQLite file.
Adding a new attribute will change the versionHash
of the NSEntityDescription
, which is why you're having this problem. If you were still migrating data from your original model, it would still work. It's only a problem because you have data that used a model version that doesn't match anything in your app right now.
To fix, do one of the following:
- Create a new third model version with this change and migrate to that, or
- Remove your existing data and migrate version 1--> 2 again, or
- Undo this most recent change so that your data continues to match your latest model version.
CoreData prevent crashing on update
The simplest way is to create a new version of the model :
http://www.raywenderlich.com/27657/how-to-perform-a-lightweight-core-data-migration
After you've make that in place you can also overide the peristentStoreCoordinator method to destroy the database and recreate it in case of extreme bad situation (user lost all his data, but the app start) by adding the code below (objc) instead of just abort it will destroy the database, and create an empty one. It can be usefull in dev, that should be a safeguard in prod but your code should never go there.
//delete the store
[[NSFileManager defaultManager] removeItemAtPath:storePath error:nil];
// recreate the store
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
Related Topics
How to Subclass Nsoperation in Swift to Queue Skaction Objects for Serial Execution
Swift: Using "/" Slash in Filename with Createdirectoryatpath
Call External Function Using Watchkit Force Touch Menuitem
How to Find the Operator Definition in Swift
What Is the Swift Equivalent of -[Nsobject Description]
Hide Password with "•••••••" in a Textfield
How to Hide Status Bar and Navigation Bar When Tap Device
Animate Cell When Pressed Using Swift 3
How to Access a Swift Enum Associated Value Outside of a Switch Statement
Can You Override Nsdateformatter 12 VS 24 Hour Time Format Without Using a Custom Dateformat
No Code Signature Found After Pod Installed in Xcode 8
Swiftui Present Alert with Input Field
Why Is the Alert Triggering Out of Order If Value Is Not Updated
How to Distinguish Between Multiple Uipickerviews on One Page
How to Say "If X == a or B or C" as Succinctly in Swift as Possible