CoreDataのマイグレーションをしようとしたときのメモ（未解決あり）


今回は、CoreDataの手動マイグレーションをやってみようとしてハマったのでそのメモです。
最終的には自動マイグレーションで終わらせました。ある程度の手動マイグレーションの感覚は掴めた気がしていますが、なぜ最後まで動かなかったのかは未解決です・・。

##マイグレーション

まず、マイグレーションの手順。


1. CoreDateのモデルファイル（XXXX.xcdatamodeld）を選択した状態でメニューから「Editor > Add Model Version…」を選択し、新しいバージョンのモデルファイルを生成

2. **新規作成した新しいバージョンのモデルデータを選択した状態で** プロパティなど、Entityを編集<br />![スクリーンショット 2014-02-05 20.48.27.png](https://qiita-image-store.s3.amazonaws.com/0/5616/d9a7d79b-c079-8fe4-42b1-7962ed32530b.png "スクリーンショット 2014-02-05 20.48.27.png")<br />*「QiitaModel 2.xcdatamodel」が新しく生成したモデルファイル*

3. 修正後、新規ファイル作成で「Core Date > Mapping Model」ファイルを生成
![スクリーンショット 2014-02-05 20.49.58.png](https://qiita-image-store.s3.amazonaws.com/0/5616/e5f0f477-3562-731c-50d1-7dc5239ede3d.png "スクリーンショット 2014-02-05 20.49.58.png")

4. 生成時、移行元と移行先のモデルデータを選択する必要があるので、移行元→移行先の順でファイルを指定してマッピングファイルを作る

5. 生成したマッピングファイルを選択し、Inspectorの「Custom Policy」の欄に、マイグレーションを処理するクラスを指定する
![cap.png](https://qiita-image-store.s3.amazonaws.com/0/5616/a6a8e334-44f3-b003-c8a6-8707ffb2fcea.png "cap.png")

6. (5)で指定したクラスを新規作成する。継承元クラスは`NSEntityMigrationPolicy`クラス

7. マイグレーションが発生した際、アプリケーションは自動でマイグレーション用のデリゲートメソッドを呼び出す

8. 1レコードあたり1回ずつデリゲートメソッドが呼ばれ、その中で移行元のコンテキストから値を取り出し、移行先のデータに手動でコピーしていく。（新規のデータについてはデフォルト値があればそこも手動で）

9. すべての処理が終わったら、無事マイグレーション完了。

*ただ、この「自動でマイグレーション用のデリゲートメソッドが呼ばれる、というところでなぜか呼ばれず、どうしても解決しなかったので自動マイグレーションで対応しました*

###サンプルコード

```objc
- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error
{
	NSManagedObjectContext *context = [manager destinationContext];
	NSString *entityName [mapping destinationEntityName];
	NSManagedObject *dInstance = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];

	[dInstance setValue:@"value1" forKey:@"anyKey1"];
	[dInstance setValue:@"value2" forKey:@"anyKey2"];
	//…

	[dInstance setValue:[sInstance valueForKey:@"existsValue1" forKey:@"existsKey1"];
	[dInstance setValue:[sInstance valueForKey:@"existsValue2" forKey:@"existsKey2"];
	//…

	return YES;
}
```

ざっくりやっていることを言うと、前のデータにあるやつはそれを取り出し新しいデータに移行し、ないのはデフォルト値なりを設定する、というもの。手動コピーみたいな感じ。
シンプルな場合はそれだけだけど、Relationとかが絡んでくると色々と大変になるはず。

見てもらうと分かるけど、ひとつの`NSManagedObject`のみ処理している。つまり、管理しているデータ件数分、このメソッドが呼ばれるということ。なので、あまりに重い場合は処理を分けるなどして起動時のタイムアウトに引っかからないようにする必要があるみたい。


###自動マイグレーションで対応

大掛かりな変更でなければ、おそらくさくっとできる自動マイグレーションで十分。
やり方は、`NSPersistentStoreCoordinator`をインスタンス化する際にオプションを指定するだけ。

```objc
//自動マイグレーション用にオプションを指定
NSDictionary *options = @{NSInferMappingAutomaticallyOption:@YES,
               NSMigratePersistentStoresAutomaticallyOption:@YES};

_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
	//Error!
}
```

###現在のModel Versionを指定する

新しくモデルを定義しても、定義の参照先を変更しないと使えません。
バージョンの変更は、CoreDataのモデルデータを選択し、Inspectorから`Model Version`を変更したいものに変更する必要があります。

![cap.png](https://qiita-image-store.s3.amazonaws.com/0/5616/c400bc08-34d1-b0b0-8918-a644abf78ee2.png "cap.png")


###マイグレーション必要かどうか判断する

マイグレーションが必要かどうかは`NSPersistentStoreCoordinator`と`NSManagedObjectContext`を使うことでチェックできる。

```objc
//meta dataを取得する
NSDictionary *sourceMetaData = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeURL error:&error];

//コンテキストに適合性を問い合わせる
BOOL isCompatible = [_managedObjectContext isConfiguration:nil compatibleWithStoreMetadata:sourceMetaData];

if (!isCompatible) {
	//マイグレーションが必要
}
```

-----------------------

##ハマったこと

マイグレーションをやってみようと思ってごにょごにょしてるときに、とりあえず元に戻そうと差分をgitから戻したあと、`Compilation failed for data model at path '/path/to/new/model.mom'`みたいなエラーでビルドできなくなった。

ファイルとかは元に戻したのになぜ・・と思っていて、↓のところの矢印部分をクリックしたら、そこに新規で作ったファイルがまだ残っていた。それのせいでエラーになっていた模様。それを消したら無事ビルドできた。

![cap.png](https://qiita-image-store.s3.amazonaws.com/0/5616/a4c18b2b-9d16-5350-cffa-5dd161548a27.png "cap.png")

-----------------------

##参考にした記事

* [[iOS][Mac] CoreData - マイグレーション[1] NSEntityMigrationPolicy を使う](http://cocoadays.blogspot.jp/2010/12/iosmac-coredata-1-nsentitymigrationpoli.html)
* [[iOS][Mac] CoreData - マイグレーション[4] モデルファイルの構成](http://cocoadays.blogspot.jp/2010/12/iosmac-coredata-%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B34-%E3%83%A2%E3%83%87%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%A7%8B%E6%88%90.html)
* [CoreData - マイグレーション](http://xcatsan.blogspot.jp/2010/05/coredata_26.html)