Before we actually release a new version of our application that migrates the data, we need to first complete a minor “maintenance” update for our users. Normally, we would add this code to the very first version of our application, but just in case we wrote that first release before versioning was a consideration, we need to go back to our old version and add a very small amount of code to help our users.
Some users will download the new version of an application to just “try it out” and see whether it’s worth the upgrade price or worth the hassle. Normally this isn’t an issue—until we upgrade the data underneath our users. Then things go sideways. What we do not want to happen is the error message shown here.
Note that this is the error message we would see on OS X. On iOS, our application would simply crash on launch. This is a terrible user experience and something we want to avoid. Fortunately, the way to avoid it is very easy, and we can add it to a point release of our application before we do any migration. That way, when the users open the first version of our application after “testing” the second version, they get a friendly error message. Or we can take it a step further and restore/access the older version of their data.
| dispatch_async(queue, ^{ |
| NSError *error = nil; |
| NSPersistentStoreCoordinator *coordinator = nil; |
| coordinator = [moc persistentStoreCoordinator]; |
| NSPersistentStore *store = nil; |
| store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType |
| configuration:nil |
| URL:storeURL |
| options:nil |
| error:&error]; |
| if (!store) { |
| ALog(@"Error adding persistent store to coordinator %@\n%@", |
| [error localizedDescription], [error userInfo]); |
| |
| NSString *msg = nil; |
| msg = [NSString stringWithFormat:@"The recipes database %@%@%@\n%@\n%@", |
| @"is either corrupt or was created by a newer ", |
| @"version of Grokking Recipes. Please contact ", |
| @"support to assist with this error.", |
| [error localizedDescription], [error userInfo]]; |
| UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" |
| message:msg |
| delegate:self |
| cancelButtonTitle:@"Quit" |
| otherButtonTitles:nil]; |
| [alertView show]; |
| return; |
| } |
This is the new creation of the persistent store inside the ‑initializeCoreDataStack method. Once we’ve initialized our persistent store coordinator, we kick off a background process to add the NSPersistentStore to the NSPersistentStoreCoordinator. If there’s an error here, we need to present it to the user and halt the application. We do this with a UIAlertView showing the error to the user, and then the delegate of the UIAlertView forces the application to quit. The resulting error message is shown here. In a production application, we would perhaps offer the user the option to reset the data as opposed to exiting. Note that we also have an ALog before the UIAlertView. When we’re developing this application, we want to make very sure that a developer-level error fires here to ideally avoid the risk of the user ever encountering it.