Detecting a Lightweight Core Data Migration

hadronzoo picture hadronzoo · Jun 11, 2010 · Viewed 7.2k times · Source

I'm using Core Data's automatic lightweight migration successfully. However, when a particular entity gets created during a migration, I'd like to populate it with some data. Of course I could check if the entity is empty every time the application starts, but this seems inefficient when Core Data has a migration framework.

Is it possible to detect when a lightweight migration occurs (possibly using KVO or notifications), or does this require implementing standard migrations?

I've tried using the NSPersistentStoreCoordinatorStoresDidChangeNotification, but it doesn't fire when migrations occur.

Answer

hadronzoo picture hadronzoo · Jun 12, 2010

To detect whether a migration is needed, check to see if the persistent store coordinator's managed object model is compatible with the existing store's metadata (adapted from Apple's Is Migration Necessary):

NSError *error = nil;
persistentStoreCoordinator = /* Persistent store coordinator */ ;
NSURL *storeUrl = /* URL for the source store */ ;

// Determine if a migration is needed
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
                                                                                          URL:storeUrl
                                                                                        error:&error];
NSManagedObjectModel *destinationModel = [persistentStoreCoordinator managedObjectModel];
BOOL pscCompatibile = [destinationModel isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata];
NSLog(@"Migration needed? %d", !pscCompatibile);

If pscCompatibile is NO, then a migration will need to occur. To examine the entity changes, compare the NSStoreModelVersionHashes key in the sourceMetadata dictionary to the [destinationModel entities]:

NSSet *sourceEntities = [NSSet setWithArray:[(NSDictionary *)[sourceMetadata objectForKey:@"NSStoreModelVersionHashes"] allKeys]];
NSSet *destinationEntities = [NSSet setWithArray:[(NSDictionary *)[destinationModel entitiesByName] allKeys]];

// Entities that were added
NSMutableSet *addedEntities = [NSMutableSet setWithSet:destinationEntities];
[addedEntities minusSet:sourceEntities];

// Entities that were removed
NSMutableSet *removedEntities = [NSMutableSet setWithSet:sourceEntities];
[removedEntities minusSet:destinationEntities];

NSLog(@"Added entities: %@\nRemoved entities: %@", addedEntities, removedEntities);