Skip to content

Instantly share code, notes, and snippets.

@irace
Last active December 15, 2015 06:28
Show Gist options
  • Save irace/5216137 to your computer and use it in GitHub Desktop.
Save irace/5216137 to your computer and use it in GitHub Desktop.
Core Data migrations are hard. If you don't need to migrate, then don't! Here's how:
/*
Core Data is great but automatic migrations can be tricky. Migrations can take a long time, which could
result in [your app being terminated](http://stackoverflow.com/questions/13333289/core-data-timeout-adding-persistent-store-on-application-launch)
if it is happening on the main thread during application launch. Performing migrations on a background
thread is also a [bad idea](http://stackoverflow.com/a/2866725/503916), meaning your application really
needs to be able to fully launch *without a Core Data stack whatsoever* in order to safely migrate.
This can be a huge change to make to an existing app.
If you're really only using Core Data as a cache, you don't actually *need* to perform a migration.
Simply check if the existing store is compatible with your managed object model and if so, delete
and recreate it. Here's my approach for doing so. Many thanks to Marcus Zarra for being *extremely*
helpful both over Twitter and on Stack Overflow.
*/
NSString *persistentStorePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,
YES) lastObject] stringByAppendingPathComponent:@"AppName.sqlite"];
// Create managed object model
NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:
[[NSBundle mainBundle] URLForResource:@"AppName"
withExtension:@"momd"]];
// Create persistent store coordinator
NSPersistentStoreCoordinator *persistentStoreCoordinator =
[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel];
// Create managed object context
managedObjectContext = [[NSManagedObjectContext alloc] init];
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator;
NSURL *persistentStoreURL = [NSURL fileURLWithPath:persistentStorePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:persistentStorePath]) {
// If store already exists, see if it is compatible with managed object model
NSError *storeMetadataError = nil;
NSDictionary *storeMetadata =
[NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:persistentStoreURL
error:&storeMetadataError];
if (storeMetadataError || ![managedObjectModel isConfiguration:nil
compatibleWithStoreMetadata:storeMetadata]) {
// Store is not compatible - wipe it
NSError *removeStoreError = nil;
[[NSFileManager defaultManager] removeItemAtPath:persistentStorePath error:&removeStoreError];
if (removeStoreError)
NSLog(@"Error removing file at path '%@': %@, %@", path, removeStoreError,
[removeStoreError userInfo]);
}
}
NSError *addStoreError = nil;
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil
URL:persistentStoreURL options:nil
error:&addStoreError])
NSLog(@"Unable to add store: %@, %@", addStoreError, [addStoreError userInfo]);
@mzarra
Copy link

mzarra commented Mar 21, 2013

I do not personally like using the instance level ivars like you are doing but otherwise the code looks fine. What problem are you having?

@irace
Copy link
Author

irace commented Mar 22, 2013

My original problem was a Core Data migration that was blocking the main thread for too long during startup. Since I'm really only using Core Data as a cache, I don't actually need to perform any migrations. This is the approach that I came up with instead, which I owe largely to your help on both Twitter and Stack Overflow.

I updated this to just use local variables instead of instance variables. This example isn't necessarily supposed to suggest where this code should live, more so just to serve as an example of the steps to take.

@mzarra
Copy link

mzarra commented Mar 22, 2013

The code looks good to me. Removing the instance level ivars removes the risk of someone overriding an accessor and doing something silly.

@irace
Copy link
Author

irace commented Mar 22, 2013

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment