Last active
August 11, 2017 17:57
-
-
Save keith/3717077 to your computer and use it in GitHub Desktop.
Some code for dealing with replacing pre-populated Core Data databases that are subject to change version by version. Place this in your `- (NSPersistentStoreCoordinator *)persistentStoreCoordinator` method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Main database location | |
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"<#(DatabaseNameAndType)#>"]; | |
NSFileManager *fileManager = [NSFileManager defaultManager]; | |
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; | |
// The Build/Bundle Version number of the application on launch | |
NSString *versionNumber = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey]; | |
// Instead of using your app's bundle version create a custom key in your Info.plist for the database version. This is probably a better idea | |
// NSString *versionNumber = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"DatabaseVersion"]; | |
// Get newest stored version from NSUserDefaults | |
NSString *newestNumber = [prefs stringForKey:NEWEST_RAN_VERSION]; | |
// Check if either the database doesn't exist or if the application is a newer version than the previously stored version | |
if (![fileManager fileExistsAtPath:[storeURL path]] || ![newestNumber isEqualToString:versionNumber]) { | |
// Get the database stored within your application's bundle | |
NSString *bundledStorePath = [[NSBundle mainBundle] pathForResource:@"<#(BundledDatabaseName)#>" ofType:@"<#(BundledDatabaseType)#>"]; | |
if ([fileManager fileExistsAtPath:bundledStorePath]) { // If bundled database exists | |
// Name of backup database and temporary backup database | |
NSURL *backupStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"<#(BackupDatabaseNameAndType)#>"]; | |
NSURL *secondBackupStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"<#(TemporaryBackupDatabaseNameAndType)#>"]; | |
if ([fileManager fileExistsAtPath:[backupStoreURL path]]) { | |
NSError *movedOldBackupError = nil; | |
// Move database backup to temporary location. You may not want to do this depending on your database's size | |
BOOL movedOldBackup = [fileManager moveItemAtURL:backupStoreURL toURL:secondBackupStoreURL error:&movedOldBackupError]; | |
if (!movedOldBackup) { | |
NSLog(@"Failed to backup %@", [movedOldBackupError localizedDescription]); | |
} | |
} | |
// Check if main database already exists | |
if ([fileManager fileExistsAtPath:[storeURL path]]) { | |
NSError *backupError = nil; | |
// Backup main database to default backup location | |
BOOL backedUp = [fileManager moveItemAtURL:storeURL toURL:backupStoreURL error:&backupError]; | |
if (backedUp) { | |
if (![fileManager fileExistsAtPath:[storeURL path]]) { | |
NSLog(@"database moved successfully"); | |
// If the second backup exists, remove it | |
if ([fileManager fileExistsAtPath:[secondBackupStoreURL path]]) { | |
// If the database was backed up sucessfully remove the temporary backup | |
NSError *removedSecondBackupError = nil; | |
BOOL removedSecondBackup = [fileManager removeItemAtURL:secondBackupStoreURL error:&removedSecondBackupError]; | |
if (!removedSecondBackup) { | |
NSLog(@"Failed to remove temporary backup %@", [removedSecondBackupError localizedDescription]); | |
} | |
} | |
} | |
} else { | |
NSLog(@"Database backup failed %@", [backupError localizedDescription]); | |
} | |
} | |
// Copy bundled database to the default location | |
NSError *error = nil; | |
BOOL copied = [fileManager copyItemAtPath:bundledStorePath toPath:[storeURL path] error:&error]; | |
if (copied) { | |
// Set newest version number to NSUserDefaults | |
NSLog(@"Copied new database"); | |
[prefs setValue:versionNumber forKey:NEWEST_RAN_VERSION]; | |
[prefs synchronize]; | |
} else { | |
NSLog(@"Copy database error %@", [error localizedDescription]); | |
// If database failed to copy attempt to copy the backup database to default location | |
if ([fileManager fileExistsAtPath:[backupStoreURL path]]) { | |
NSError *moveOldDatabaseError = nil; | |
BOOL movedOldDatabase = [fileManager copyItemAtURL:backupStoreURL toURL:storeURL error:&moveOldDatabaseError]; | |
if (movedOldDatabase) { | |
NSLog(@"Copied old database to default location"); | |
} else { | |
// No database exists. Epic fail. | |
NSLog(@"Failed to copy old database %@", [moveOldDatabaseError localizedDescription]); | |
#warning Refrain from using `abort();` in production level code (says Apple) | |
abort(); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment