[解決済み] 複数パスによるCore Data Migrationの例と解説?
質問
私の iPhone アプリは、コア データ ストアを移行する必要があり、一部のデータベースは非常に大きいです。 Apple のドキュメントでは、メモリの使用量を減らすために、データの移行に複数のパスを使用することを提案しています。 しかし、ドキュメントは非常に限られており、実際にこれを行う方法についてあまりよく説明していません。どなたか良い例を示してくださるか、または実際にこれを実行する方法のプロセスを詳細に説明していただけないでしょうか。
どのように解決するのですか?
私は、Apple が彼らの ドキュメント . 実はとても簡単なことなのですが、明白になるまでには長い道のりがあります。例を挙げて説明します。最初の状況はこうです。
データモデル バージョン 1
これは、"コア データ ストレージ付きナビゲーション ベース アプリ" テンプレートでプロジェクトを作成したときに取得されるモデルです。これをコンパイルして、for ループの助けを借りて、異なる値を持つ約 2,000 のエントリを作成するために、いくつかのハードヒットを行ってみました。NSDate 値を持つ 2,000 個のイベントを作成しました。
次に、次のようなデータモデルの2番目のバージョンを追加します。
データモデル 第二版
違うのは Eventエンティティがなくなり、新たに2つのエンティティが追加されました。一つは、タイムスタンプを
double
として保存するもの、そしてもう一つは日付を
NSString
.
目標は、すべての バージョン 1 イベントを 2 つの新しいエンティティに転送し、移行に伴って値を変換することです。この結果、2 倍の値がそれぞれ別のエンティティの別のタイプとして存在することになります。
移行するには、手作業で移行を選択し、これをマッピングモデルで行います。これは、ご質問に対する回答の最初の部分でもあります。2kのエントリを移行するのに時間がかかり、メモリフットプリントを低く抑えたいので、移行は2段階で行います。
これらのマッピングモデルをさらに分割して、エンティティの範囲のみを移行することもできます。たとえば、100 万件のレコードがあるとすると、プロセス全体がクラッシュする可能性があります。取得したエンティティを フィルタ述語 .
2つのマッピングモデルに戻ります。
最初のマッピングモデルはこのように作成します。
1. 新規ファイル -> リソース -> マッピングモデル
2. 名前を決めてください、私はStepOneを選びました
3. 送信元と送信先のデータモデルを設定する
マッピングモデル ステップ1
マルチパス移行では、カスタムエンティティ移行ポリシーは必要ありませんが、この例ではもう少し詳細な情報を得るために、これを実行します。そこで、エンティティにカスタム ポリシーを追加します。これは常に
NSEntityMigrationPolicy
.
このポリシークラスは、マイグレーションを実現するためのいくつかのメソッドを実装しています。しかし、今回はシンプルなので、1つのメソッドだけを実装すればよいでしょう。
createDestinationInstancesForSourceInstance:entityMapping:manager:error:
.
実装はこのようになります。
StepOneEntityMigrationPolicy.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
をバンドルしています。 -
移行先のストアは提供する必要があり、移行元のストアであってはなりません。移行が成功したら、古いストアを削除し、新しいストアの名前を変更することができます。
-
マッピングモデルを作成した後にデータモデルに変更を加えたところ、互換性エラーが発生し、マッピングモデルを再作成することでしか解決できなくなりました。
関連
-
[解決済み] コア・データ エンティティの全インスタンスを削除する最短の方法
-
[解決済み] UIImage。リサイズ、そしてクロップ
-
[解決済み] APNSの.pemファイルを作成する?
-
[解決済み] iphone Core Data 保存時に未解決のエラーが発生する。
-
[解決済み] NSDictionaryをNSDataに、またはNSDataをNSDictionaryに変換するにはどうすればよいですか?
-
[解決済み] Xcode 4.2 - '...' の宣言は、この関数の外では表示されません 警告
-
[解決済み] UIWebViewの背景がクリアカラーに設定されているが、透明になっていない
-
[解決済み] UILabelがラベルサイズに合うようにテキストを自動縮小しない
-
[解決済み] iPhone-Portrait-NumberPadキーボードでタイプ4をサポートするキープレインが見つからない; 3876877096_Portrait_iPhone-Simple-Pad_Defaultを使用
-
[解決済み] iOS 5における高速かつ効率的なCoreデータインポートの実装
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Objective-CでENUMを定義して使用するにはどうすればよいですか?
-
[解決済み] レビュー待ちの状態でバイナリを拒否する(バイナリ拒否ボタンが見つからない)
-
[解決済み] ITunesのレビューURLとiOS 7(ユーザーにアプリを評価してもらう)AppStoreに空白のページが表示される。
-
[解決済み] インスタンスからクラス名を取得する
-
[解決済み] drawRectを使うか使わないか(drawRect/Core Graphicsとsubview/imagesをいつ使うか、なぜ使うか)?
-
[解決済み] リンカーフラグ -ObjC は何をするのですか?
-
[解決済み] iphoneシミュレーターでキーボードを使うにはどうしたらいいですか?
-
[解決済み] 円形のカスタムUIViewの描き方 - iPhoneアプリ
-
[解決済み] AppDelegate.mで画面上に現在表示されているUIViewControllerを取得する。
-
[解決済み] 現在のメソッド呼び出しのスレッド ID を取得する