2012年3月25日日曜日

Core Data 自動マイグレーション


おおまかな手順は次のとおりです。
現在のxcdatamodelファイルをModel.xcdatamodelとします。

1.Xcode左ペインで Model.xcdatamodel を選択する。

2.メニューのEditorから"Add Model Version..."を選択する。

3.保存名(デフォルト:Model 2.xcdatamodel)、保存先を設定/選択する。

4.保存すると、次のようなModel.xcdatamodeldが作られる。
    Model.xcdatamodeld
      Model.xcdatamodel
      Model 2.xcdatamodel
   
5.Model 2.xcdatamodelをカレントモデルに設定する。

6.自動マイグレーションのためのコードを実装する。

自動マイグレーションの実装例
(Core Dataの追加でメソッドを実装した場合)

MYAppDelegate.m

#import "MYAppDelegate.h"
#import "Person.h"

@implementation MYAppDelegate
{
    NSManagedObjectContext *_managedObjectContext;
    NSPersistentStoreCoordinator *_persistentStoreCoordinator;
    NSManagedObjectModel *_managedObjectModel;
}

- (NSManagedObjectContext *)managedObjectContext {
    if (_managedObjectContext == nil) {
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
        if (coordinator != nil) {
            _managedObjectContext = [[NSManagedObjectContext alloc] init];
            [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        }
    }
    return _managedObjectContext;
}

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

//プロパティpersistentStoreCoordinatorのgetterメソッド。
//persistentStoreCoordinatorWithOptionをoption=nilで呼び、その戻り値を返す。
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    return [self persistentStoreCoordinatorWithOption:nil];
}

//オプション指定可のpersistentStoreCoordinator getterメソッド。migrarion時にオプションを追加する。
- (NSPersistentStoreCoordinator *)persistentStoreCoordinatorWithOption:(NSDictionary *)options
{
    if (_persistentStoreCoordinator == nil) {
        _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
                                       initWithManagedObjectModel:[self managedObjectModel]];
     
        NSError *error = nil;
        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                      configuration:nil
                                                                URL:[self coreDataStoreURL]
                                                            options:options
                                                              error:&error])
        {
           //エラー処理
            NSLog(@"persistentStoreCoordinator: Error %@, %@", error, [error userInfo]);
        }
    }
    return _persistentStoreCoordinator;
}

//アプリケーションのDocumentsフォルダ。CoreDataをここに保存する。
- (NSString *)applicationDocumentsDirectory {
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}

//Core Data保存先。保存先がひとつだけの場合。
- (NSURL *)coreDataStoreURL
{
    return [NSURL fileURLWithPath:[[self applicationDocumentsDirectory]
                                   stringByAppendingPathComponent: @"CoreData.sqlite"]];
}

//---------- Core Data Migration 関連 ----------

//CurrentのModelと保存されているCoreDateと整合がとれているかチェック。
//不整合の場合はマイグレーションが必要なのでYESを返す。
- (BOOL)shouldPerformCoreDataMigration
{
    NSError *error = nil;  
    NSDictionary *storeMetadata = [NSPersistentStoreCoordinator
                                    metadataForPersistentStoreOfType:NSSQLiteStoreType
                                    URL:[self coreDataStoreURL]
                                    error:&error];
 
    if (storeMetadata == nil)
    {
        return NO;
    }
    //NSManagedObjectModel *destinationModel = [self managedObjectModel];
    BOOL isCompatibile = [[self managedObjectModel]
                          isConfiguration:nil
                          compatibleWithStoreMetadata:storeMetadata];
    return !isCompatibile;
}

//Core Dataの自動マイブレーションを行う。成功した場合はYES、失敗の場合はNOを返す。
- (BOOL)performMigration
{
    //自動マイグレーションのためのオプション
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
    //_persistentStoreCoordinatorを作り直すためnilにし、persistentStoreCoordinatorWithOptionを呼ぶ。
    _persistentStoreCoordinator = nil;
    [self persistentStoreCoordinatorWithOption:options];      
    NSError *error;
    if (error)
    {
        //エラー処理
        NSLog(@"error: %@", error);
        return NO;
    }
    return YES;
}

//--------- UIApplication delegate / 起動直後にマイグレーションを実行する ---------

- (BOOL)application:(UIApplication *)application
             didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    NSPersistentStoreCoordinator *persistentStoreCoordinator =  [self persistentStoreCoordinator];
    // update
    if ([self shouldPerformCoreDataMigration])
    {
        if ([self performMigration] == NO)
        {
            _persistentStoreCoordinator = nil;
        }
        [self persistentStoreCoordinator];
    }
    return YES;
}

@end


0 件のコメント: