HOME » Natsu note » 古い投稿 » Core Data 勉強日記 (8):More iPhone 3 Development / chapter 5 (データモデルのバージョン管理)

Core Data 勉強日記 (8):More iPhone 3 Development / chapter 5 (データモデルのバージョン管理) 2010/02/20/|古い投稿

この記事は情報が古い可能性があります。参照する際にはご注意ください。

More iPhone 3 Development: Tackling iPhone SDK 3 (Beginning) Chapter 5 のまとめ。

まずはじめに、Core Dataを利用して保存したデータは、データモデルに変更があると、そのままでは使えなくなる。データモデルを変更したにも関わらず、旧構成のデータが保存されている状態では、アプリは起動すらできない。
かといって、初回リリース時に今後のすべてのアップデートまで見越したデータ構成にしておくことは難しい。そこで、データモデルのバージョン管理が必要になるのだ。

Core Dataの勉強を始めたばかりの頃、このことを知らずに結構はまったっけ。
一瞬、データモデルの変更はできないのか??と思ったりもしたけれど、そんなことはないです。困りますから・・・。

新バージョンの作成

データモデルを編集する前に必ず新しいバージョンのモデルを作成する。
該当する .xcdatamodel ファイルを選択し、メニューバーから、「設計」→「データモデル」→「モデルバージョンを追加」を選ぶ。これで、既存のデータモデルのコピーができあがる。

Xcdatamodel versioning

ファイルリストを見ると、このようにひとつバージョンが増えているのがわかる。

Added xcdatamodel


緑のチェックマークがついているのが現(新しい)バージョンだ。デフォルト動作では、末尾についているバージョン番号が大きくなればなるほど古いということになる。ここは要注意。
要は、毎回バックアップをとるといったイメージである。変更していくのは常に同じ名前のファイルでよい。

もちろん、必要があれば現バージョンを変更することもできるし、バージョン名を変更することも可能。

データモデルの読み込み

バージョン管理されていない(ひとつしかない)データモデルは、コンパイラにより.momファイルに変換される。一方、バージョン管理済みのデータモデルは、.momdとなる。
ManagedObjectModelのクラスメソッドmergedModelFromBundlesを使うと、バンドル内にあるモデルをすべて読み込むことができる。Xcodeのテンプレートでもこの方法を使っている(以下)。.momファイルも.momdファイルもこれで読み込み可能だが、ビルド時にクリーンをし忘れたりすると、やや面倒なことになる(可能性がある)。

- (NSManagedObjectModel *)managedObjectModel {
    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
    return managedObjectModel;
}

確実にバージョンつけされている現データモデルを読み込みたければ、以下のように変更すればよい。

- (NSManagedObjectModel *)managedObjectModel {
    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
    NSString *path = [[NSBundle mainBundle] pathForResource:@"SuperDB" ofType:@"momd"];
    NSURL *momURL = [NSURL fileURLWithPath:path];
    managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
    return managedObjectModel;
}

このようにしておくと、Core Data は、バージョン付けされた.momdファイルのみを読み込み、.momは、バージョン移行に必要な場合にのみ利用される。

データモデルのバージョン移行

データモデルのバージョン移行(移植?)には二通りあるが、ここでは簡易な移行のみを使う。基本的に、attributeやentityの追加/削除は、この方法が使える。

データモデルを新しいバージョンへ移行するためには、NSPersistentStoreCoordinatorを生成するメソッドにオプションを指定すれば、あとは自動でやってくれる。
– (NSPersistentStoreCoordinator *) persistentStoreCoordinator(だいたいAppDelegate内にある)に注目。テンプレートでは以下のようになっている。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
	}
	NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] 
              stringByAppendingPathComponent: @"SuperDB.sqlite"]];
	NSError *error = nil;
	persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
	if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
		NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
		abort();
	}
	return persistentStoreCoordinator;
}

addPErsistentStoreWithType:configuration:URL:options:error: のoptionsに、データ移行オプションを指定する。オプションの指定にはNSDictionaryを用いる。

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                         [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                         [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, 
                         nil];

これを、上記メソッドのoptions:に渡してあげればよい。これで、データモデル変更後も、正しく動作するようになる。

More iPhone 3 Development: Tackling Iphone Sdk 3 (Beginning)
Dave Mark Jeff Lamarche
Apress
売り上げランキング: 29207