大幅な変更が必要な iOS アプリを継承しました。現在の形式では、単一の UIManagedDocument (iCloud と同期されていませんが、Core Data ボイラープレートを回避するためにのみ使用されます) を使用してユーザー データを格納します。データ モデルを大幅に変更する必要があり、通常の Core Data スタックに切り替えたいと考えています。既存のコードベースもかなり使い物にならなかったので、新しいプロジェクトを作成することにしましたが、同じアプリ ID を使用して更新として公開できるようにしました。
既存のユーザーのデータを新しいデータ モデルにインポートする方法がわかりません。
現在のモデルには 3 つの主要なエンティティがあり、それぞれのエンティティから 2 つの属性のみが必要です (残りの古いデータは破棄できます)。新しいデータ モデルを作成した後、以前のプロジェクトのすべての古いモデル ファイルと古いデータ モデルをコピーしました。
次に、インポーター クラスを作成しました。
-(BOOL)isImportNeeded
{
return [[NSFileManager defaultManager] fileExistsAtPath:[[self URLToOldModel] path]];
}
-(NSURL*)URLToOldModel
{
NSURL* URL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
return [URL URLByAppendingPathComponent:@"Data"];
}
-(UIManagedDocument*)managedDocumentAtPath:(NSString*)path
{
return [[UIManagedDocument alloc] initWithFileURL:[self URLToOldModel]];
}
-(void)performWithDocument:(void (^)(void))onDocumentReady
{
if (self.managedDoc.documentState == UIDocumentStateClosed) {
// I put this code here for debug purposes
NSError* e = nil;
if (![self.managedDoc readFromURL:self.managedDoc.fileURL error:&e]) {
NSLog(@"Couldn't read UIManagedDocument: %@", [e localizedDescription]);
}
// [self.managedDoc openWithCompletionHandler:^(BOOL success){
// if (success)
// onDocumentReady();
// else
// NSLog(@"Could not open document");
// }];
}
else if (self.managedDoc.documentState == UIDocumentStateNormal)
{
onDocumentReady();
}
}
-(void)import
{
self.managedDoc = [self managedDocumentAtPath:[[self URLToOldModel] path]];
self.sourceManagedObjectContext = self.managedDoc.managedObjectContext;
[self performWithDocument:^{ ... }];
}
エラーの辞書をもう少し掘り下げると、エラーの理由としてNSLog
次のように表示されます。「ストアを開くために使用されたモデルは、ストアを作成するために使用されたモデルと互換性がありません」.Couldn't read UIManagedDocument: The operation couldn’t be completed. (Cocoa error 134100.)
userInfo
古いデータ モデルがプロジェクトに追加され、「ソースのコンパイル」ビルド フェーズにあることを確認しました。
UIManagedDocument についてさらに学び、初期化されると、バンドル内のすべてのデータ モデルの結合が自動的に作成され、これを停止する方法は、UIManagedDocument をサブクラス化し、アクセサーをオーバーライドすることであることに気付きましたmanagedObjectModel
。次のメソッドだけでサブクラスを作成することで、そうしました。
-(NSManagedObjectModel*)managedObjectModel
{
NSString* modelPath = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"momd"];
modelPath = [modelPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* modelURL = [NSURL URLWithString:modelPath];
return [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
}
ただし、それでも同じエラーが発生します。