[前回] Cocoaの日々: [iOS][Mac] CoreData - マイグレーション[1] NSEntityMigrationPolicy を使う
NSEntityMigrationPolicy を使うことで複雑なマイグレーションを行うことができる。前回は NSDate から月と日を抽出するコードを書いたが、これぐらいであれば自動マイグレーション(Lightweigt Migration)が使えないだろうか。ドキュメントを読み返していると FUNCTION が使えそうなのがわかったのでこれを試してみる。
サンプル
まずは結果から。前回のコードを書き換えて自動マイグレーションに切り替えた。マッピングモデルはこんな感じ。
前回と同じ。後で説明するが NSEntityMigrationPolicy を今回も使う。
day と month の値式に今回は FUNCTION を記述。
FUNCTION($entityPolicy, "monthOfDate:" , $source.timeStamp)ドキュメントを見つけられなったので推測になるが FUNCTION は最初の引数にメッセージを投げる先のインスタンス、2番目にセレクタ(文字列)、3番目以降がセレクタの引数、といった仕様のようだ。指定したインスタンスへ指定した引数でメッセージを投げ、その結果が移行先の属性値として使われる。
$entityPolicy は「カスタムポリシー」で指定したクラスのインスタンスを指す。今回は NSEntityMigrationPolicy のサブクラス EventEntityMigrationPolicy を指定した。この $ で始まる予約語には次のものがある。
NSMigrationManagerKey: $manager NSMigrationSourceObjectKey: $source NSMigrationDestinationObjectKey: $destination NSMigrationEntityMappingKey: $entityMapping NSMigrationPropertyMappingKey: $propertyMapping NSMigrationEntityPolicyKey: $entityPolicyCore Data Model Versioning and Data Migration Programming Guide: Mapping Overview より転載)
EventEntityMigrationPolicy の実装はこう。
@implementation EventEntityMigrationPolicy - (NSNumber*)monthOfDate:(NSDate*)date { NSCalendar* calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; NSDateComponents* components = [calendar components:NSMonthCalendarUnit| NSDayCalendarUnit fromDate:date]; return [NSNumber numberWithInteger:[components month]]; } - (NSNumber*)dayOfDate:(NSDate*)date { NSCalendar* calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; NSDateComponents* components = [calendar components:NSMonthCalendarUnit| NSDayCalendarUnit fromDate:date]; return [NSNumber numberWithInteger:[components day]]; }
前回の create..メソッドはコメントアウトしてある。
備考
FUNCTION のターゲットオブジェクト
Event という名前の NSManagedObjectContext をサブクラスを用意して、そこに -dayOfDate: -monthOfDate: を実装したが、実行時にはエラーとなった。
e[8858:207] -[NSManagedObject monthOfDate:]: unrecognized selector sent to instance 0x4d87c10 [8858:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject monthOfDate:]: unrecognized selector sent to instance 0x4d87c10'
モデル定義でクラス指定しても駄目だった。
本来はここにマイグレーションコードが書けるといいのだが(NSEntityMigrationPolicyのインスタンスを用意する必要がなくなる)。
属性マッピングの値式に文字列を指定
属性マッピングの値式に文字列を書くときは ""で囲う。◯ "Hello" × Hello ※ null扱いになる
ソースコード
GitHub からどうぞ。
xcatsan/iOS-Sample-Code at 2010-12-07 - GitHub
Responses
Leave a Response