これを回避するためには、事前にマイグレーションが必要かどうかを判定すればよい。
[ AppDelegate.m ]
didFinishLaunchingWithOptions
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptionsアプリ起動時、didFinishLaunchingWithOptionsにて、shouldPerformCoreDataMigrationメソッドを軌道してマイグレーションが必要かを判定する。
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
// Migration start
if ([self shouldPerformCoreDataMigration])
{
if ([self performMigration] == NO)
{
__persistentStoreCoordinator = nil;
}
[self persistentStoreCoordinator];
}
// Migration end
MasterViewController *masterViewController = [[[MasterViewController alloc] initWithNibName:@"MasterViewController" bundle:nil] autorelease];
self.navigationController = [[[UINavigationController alloc] initWithRootViewController:masterViewController] autorelease];
masterViewController.managedObjectContext = self.managedObjectContext;
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
次にマイグレーションが必要であれば、performMigrationメソッドを呼び出してマイグレーション処理を実行する。マイグレーション実行後、persistentStoreCoordinatorメソッドを通してpersistentStoreCoordinatorインスタンスを作り直す。
managedObjectContext
- (NSManagedObjectContext *)managedObjectContextmanagedObjectContextはテンプレート(Xcodeで自動生成したクラス)から変更なし。
{
if (__managedObjectContext != nil) {
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; // options = nilで実行(migrationなし)
if (coordinator != nil) {
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
persistentStoreCoordinatorメソッドが呼び出されたとき、options = nilで実行されるため、マイグレーション処理は行わない。
managedObjectModel
- (NSManagedObjectModel *)managedObjectModelmanagedObjectModelはテンプレート(Xcodeで自動生成したクラス)から変更なし。
{
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataMigrationTest" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
persistentStoreCoordinator
- (NSPersistentStoreCoordinator *)persistentStoreCoordinatorpersistentStoreCoordinatorは、テンプレートではNSPersistentStoreCoordinator処理の記述を行っているのだが、ここからpersistentStoreCoordinatorWithOptionメソッドを オプション:nilつきで呼び出して実行するように修正する。
{
return [self persistentStoreCoordinatorWithOption:nil];
}
persistentStoreCoordinatorWithOption
- (NSPersistentStoreCoordinator *)persistentStoreCoordinatorWithOption:(NSDictionary *)optionspersistentStoreCoordinatorWithOption:optionsは、新たに追加するメソッドで、optionsはnilの場合とmigration処理用に設定されている場合の2通りで呼び出される。
{
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMigrationTest.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(@"persistentStoreCoordinatorWithOption Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
persistentStoreCoordinatorインスタンスはここで作られる。optionsにnilが設定されている場合はマイグレーションは行われない。
shouldPerformCoreDataMigration
- (BOOL)shouldPerformCoreDataMigrationshouldPerformCoreDataMigrationはマイグレーション要否判定処理。
{
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMigrationTest.sqlite"];
NSError *error = nil;
NSDictionary *storeMetadata = [NSPersistentStoreCoordinator
metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:storeURL
error:&error];
if (storeMetadata == nil)
{
return NO;
} else if (error) {
NSLog(@"Checking migration was failed (%@, %@)", error, [error userInfo]);
abort();
}
BOOL isCompatibile = [[self managedObjectModel]
isConfiguration:nil
compatibleWithStoreMetadata:storeMetadata];
return !isCompatibile;
}
カレントのデータモデルと、保存されているCore Dataとで、整合がとれているかチェックを行い、不整合がある場合はマイグレーションが必要なのでYESを返している。
performMigration
- (BOOL)performMigrationperformMigrationはマイグレーション処理の事前処理で、NSDictionary型のoptionsに自動マイグレーションのためのオプションを編集し、persistentStoreCoordinatorWithOptionにこのoptionsを設定して、persistentStoreCoordinatorインスタンスを作る。
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
__persistentStoreCoordinator = nil;
[self persistentStoreCoordinatorWithOption:options];
// NSError *error;
NSError *error = nil;
if (error)
{
//エラー処理
NSLog(@"performMigration error: %@", error);
return NO;
}
return YES;
}
参考記事:
http://ken-plus.blogspot.jp/2012/03/core-data-model.html
http://cocoadays.blogspot.jp/2011/02/coredata-coredatamanager.html
http://cocoadays.blogspot.jp/2011/02/iosmac-coredata.html
http://yoo-s.com/topic/detail/381