複数のパスを使用したコアデータ移行の例または説明はありますか? 質問する

複数のパスを使用したコアデータ移行の例または説明はありますか? 質問する

私の iPhone アプリはコア データ ストアを移行する必要があり、一部のデータベースは非常に大きいです。Apple のドキュメントでは、メモリ使用量を削減するために「複数のパス」を使用してデータを移行することを推奨しています。しかし、ドキュメントは非常に限られており、実際にこれを行う方法についてはあまりよく説明されていません。誰か良い例を教えてくれるか、実際にこれを実現するプロセスを詳しく説明してくれませんか?

ベストアンサー1

私はアップルが何を示唆しているのか理解したドキュメンテーション実はとても簡単ですが、それが明らかになるまでには長い道のりがあります。例を挙げて説明しましょう。最初の状況は次のようになります。

データモデル バージョン 1

ここに画像の説明を入力してください ここに画像の説明を入力してください

これは、「コア データ ストレージを備えたナビゲーション ベースのアプリ」テンプレートを使用してプロジェクトを作成するときに取得するモデルです。これをコンパイルし、for ループを使用してハード ヒットを実行し、すべて異なる値を持つ約 2,000 個のエントリを作成しました。NSDate 値を持つ 2,000 件のイベントが作成されました。

ここで、次のようなデータ モデルの 2 番目のバージョンを追加します。

ここに画像の説明を入力してください

データモデル バージョン 2

違いは、Event エンティティがなくなり、新しいエンティティが 2 つあることです。1 つはタイムスタンプを として保存しdouble、もう 1 つは日付を として保存しますNSString

目標は、すべてのバージョン 12 つの新しいエンティティにイベントを追加し、移行に沿って値を変換します。これにより、別々のエンティティに異なるタイプの値が 2 倍になります。

移行するには、手動での移行を選択し、これをマッピング モデルで行います。これは、質問に対する回答の最初の部分でもあります。2,000 エントリの移行には時間がかかり、メモリ フットプリントを低く抑えたいため、移行は 2 つのステップで行います。

これらのマッピングモデルをさらに分割して、エンティティの範囲のみを移行することもできます。たとえば、100万件のレコードがある場合、プロセス全体がクラッシュする可能性があります。取得するエンティティを絞り込むには、フィルター述語

2 つのマッピング モデルに戻ります。

最初のマッピング モデルは次のように作成します。

1. 新規ファイル -> リソース -> マッピング モデル ここに画像の説明を入力してください

2. 名前を選択します。私はStepOneを選択しました。

3. ソースと宛先のデータモデルを設定する

ここに画像の説明を入力してください

マッピングモデル ステップ 1

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここに画像の説明を入力してください

マルチパス移行ではカスタムエンティティ移行ポリシーは必要ありませんが、この例ではもう少し詳細にするためにそれを行います。エンティティにカスタムポリシーを追加します。これは常にNSEntityMigrationPolicy

ここに画像の説明を入力してください

このポリシー クラスは、移行を実現するためのいくつかのメソッドを実装します。ただし、この場合は単純なので、実装する必要があるメソッドは 1 つだけです。createDestinationInstancesForSourceInstance:entityMapping:manager:error:

実装は次のようになります。

ステップワンエンティティ移行ポリシー.m

#import "StepOneEntityMigrationPolicy.h"


@implementation StepOneEntityMigrationPolicy

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance 
                                      entityMapping:(NSEntityMapping *)mapping 
                                            manager:(NSMigrationManager *)manager 
                                              error:(NSError **)error
{
    // Create a new object for the model context
    NSManagedObject *newObject = 
        [NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName] 
                                      inManagedObjectContext:[manager destinationContext]];

    // do our transfer of nsdate to nsstring
    NSDate *date = [sInstance valueForKey:@"timeStamp"];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];    

    // set the value for our new object
    [newObject setValue:[dateFormatter stringFromDate:date] forKey:@"printedDate"];
    [dateFormatter release];

    // do the coupling of old and new
    [manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];

    return YES;
}

最終ステップ:移行そのもの

2 番目のマッピング モデルを設定する部分は省略します。この部分はほぼ同じで、NSDate を double に変換するために使用される timeIntervalSince1970 だけです。

最後に、移行を開始する必要があります。定型コードはここでは省略します。必要な場合は、ここに投稿します。次の場所にあります。移行プロセスのカスタマイズこれは最初の2つのコード例をマージしただけです。3番目と最後の部分は次のように変更されます。NSMappingModelクラスmappingModelFromBundles:forSourceModel:destinationModel:私たちはinitWithContentsOfURL:クラス メソッドは、バンドル内で見つかったマッピング モデルを 1 つだけ (おそらく最初に見つかったもの) 返すためです。

これで、ループの各パスで使用できる 2 つのマッピング モデルができました。移行マネージャーに migrate メソッドを送信します。これで完了です。

NSArray *mappingModelNames = [NSArray arrayWithObjects:@"StepOne", @"StepTwo", nil];
NSDictionary *sourceStoreOptions = nil;

NSURL *destinationStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMigrationNew.sqlite"];

NSString *destinationStoreType = NSSQLiteStoreType;

NSDictionary *destinationStoreOptions = nil;

for (NSString *mappingModelName in mappingModelNames) {
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:mappingModelName withExtension:@"cdm"];

    NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];

    BOOL ok = [migrationManager migrateStoreFromURL:sourceStoreURL
                                               type:sourceStoreType
                                            options:sourceStoreOptions
                                   withMappingModel:mappingModel
                                   toDestinationURL:destinationStoreURL
                                    destinationType:destinationStoreType
                                 destinationOptions:destinationStoreOptions
                                              error:&error2];
    [mappingModel release];
} 

ノート

  • マッピング モデルはcdmバンドル内で終了します。

  • 移行先ストアを指定する必要があり、ソース ストアであってはなりません。移行が成功したら、古いストアを削除し、新しいストアの名前を変更できます。

  • マッピング モデルの作成後にデータ モデルにいくつか変更を加えたところ、互換性エラーが発生しました。このエラーは、マッピング モデルを再作成することによってのみ解決できました。

おすすめ記事