Short question:
I want to run a certain code in my app only if my Core Data model has changed (new entities, new properties, etc). How can I determine if the model has changed or not?
Just some pseudo-code:
if (current_model_version != previous_model_version) {
//do some code
} else {
// do some other code
}
I'm guessing I might use versionHashes to do this, or isConfiguration:compatibleWithStoreMetadata:, but I'm not certain how.
Some editing for clarity: 'current' as in 'now' and 'previous' as in 'last time app was launched.'
The answer seems to be isConfiguration:compatibleWithStoreMedia:.
I found some useful information here:
http://mipostel.com/index.php/home/70-core-data-migration-standard-migration-part-2
I set it up this way:
- (BOOL)modelChanged
{
NSError *error;
NSURL * sourceURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"db.sqlite"];
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:sourceURL error:&error];
BOOL isCompatible = [[self managedObjectModel] isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata];
return isCompatible;
}
'self' is my shared data store, not that it necessarily has to go there.
deanWombourne points out that what this really does is determine whether or not the data can be automatically migrated, so it's not exactly the solution to the problem I posed. It does serve my needs in this case.
This is replacement code for - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
that you get if you tick the Core Data box when setting up a new project in XCode.
It attempts to open the existing sqlite file (using lightweight migration if necessary). If that fails, it deletes and re-creates the store.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSError *error = nil;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:options error:&error])
{
NSLog(@"Couldn't open the store. error %@, %@", error, [error userInfo]);
[self deleteSqliteFilesForStore:self.storeURL];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:options error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
// or [NSException raise ...]
}
else
{
NSLog(@"Store deleted and recreated");
// TEST DATA RE-INITIALIZATION CODE GOES HERE
}
}
else
{
NSLog(@"Existing Store opened successfully");
}
return _persistentStoreCoordinator;
}
- (void)deleteSqliteFilesForStore:(NSURL *)storeURL
{
NSURL *baseURL = [storeURL URLByDeletingPathExtension];
// Delete the associated files as well as the sqlite file
for (NSString *pathExtension in @[@"sqlite",@"sqlite-shm",@"sqlite-wal"])
{
NSURL *componentURL = [baseURL URLByAppendingPathExtension:pathExtension];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[componentURL path]];
if(fileExists)
{
[[NSFileManager defaultManager] removeItemAtPath:[componentURL path] error:nil];
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With