Core Data で SQLite ストアの軽量移行を行おうとしています。Xcode 4.3.1 で Lion 10.7.3 に取り組んでいます。
NSPersistentDocument サブクラス (AccountDocument) で、永続ストア コーディネーターの構成に使用するメソッドをオーバーライドして、移行に適切なオプションを取得できるようにしました。
- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError **)error
{
NSMutableDictionary *newStoreOptions;
if (storeOptions == nil) {
newStoreOptions = [NSMutableDictionary dictionary];
}
else {
newStoreOptions = [storeOptions mutableCopy];
}
[newStoreOptions setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[newStoreOptions setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
BOOL result = [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:newStoreOptions error:error];
return result;
}
(そのヒントについて Malcolm Crawford に感謝します: http://homepage.mac.com/mmalc/CocoaExamples/controllers.html )
アプリを実行すると、NSPersistentDocument の次の実装で失敗します-managedObjectModel
。
* thread #1: tid = 0x2703, 0x00007fff931d9350 libobjc.A.dylib`objc_msgSend_vtable13 + 16, stop reason = EXC_BAD_ACCESS (code=13, address=0x0)
frame #0: 0x00007fff931d9350 libobjc.A.dylib`objc_msgSend_vtable13 + 16
frame #1: 0x00007fff8935e975 CoreData`-[NSKnownKeysDictionary1 _setValues:retain:] + 197
frame #2: 0x00007fff8935f288 CoreData`_newReadModelFromBytes + 648
frame #3: 0x00007fff8935b93e CoreData`+[NSManagedObjectModel(_NSManagedObjectModelPrivateMethods) _newModelFromOptimizedEncoding:error:] + 9310
frame #4: 0x00007fff89359451 CoreData`-[NSManagedObjectModel(_NSManagedObjectModelPrivateMethods) initWithContentsOfOptimizedURL:] + 305
frame #5: 0x00007fff89358d7b CoreData`-[NSManagedObjectModel initWithContentsOfURL:] + 443
frame #6: 0x00007fff893e9519 CoreData`+[NSManagedObjectModel mergedModelFromBundles:] + 377
frame #7: 0x00007fff8ded7037 AppKit`-[NSPersistentDocument managedObjectModel] + 301
frame #8: 0x00007fff8ded70b3 AppKit`-[NSPersistentDocument managedObjectContext] + 75
frame #9: 0x00007fff8ded6e3f AppKit`-[NSPersistentDocument _persistentStoreCoordinator] + 18
frame #10: 0x00007fff8ded6b5d AppKit`-[NSPersistentDocument configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:] + 51
frame #11: 0x0000000100003193 BeanCounter`-[AccountDocument configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:] + 419 at AccountDocument.m:298
ドキュメントからわかることから、デフォルトの実装は次のようになります。
- (id)managedObjectModel
{
NSManagedObjectModel *result = [NSManagedObjectModel mergedModelFromBundles:nil];
return result;
}
したがって、問題をもう少しデバッグするために、そのメソッドを次のようにオーバーライドしました。
- (id)managedObjectModel
{
NSBundle *bundle = [NSBundle mainBundle];
NSURL *url = [bundle URLForResource:@"AccountDocument2" withExtension:@"momd"];
NSManagedObjectModel *result = [[[NSManagedObjectModel alloc] initWithContentsOfURL:url] autorelease];
return result;
}
(アイデアを提供してくれた Jeff LaMarche に感謝します: http://iphonedevelopment.blogspot.com/2009/09/core-data-migration-problems.html )
バンドルと URL は両方とも、私が期待する場所を指しています (そして、Marcus Zarra のアドバイスに従い、プロジェクトをクリーンアップして、アプリケーション パッケージに不要な .mom または .momd バンドルがないようにしました: MergedModelFromBundles の使用: とバージョン管理 (CoreData))。それでも、URL からモデルをロードしている間、アプリは引き続きクラッシュします。
AccountDocument2.xcdatamodeld がバージョン管理用の 2 つのモデルを持つパッケージであることを確認しました: AccountDocument 2.xcdatamodel と (元の) AccountDocument.xcdatamodel。ファイル プロパティの [Versioned Core Data Model] ポップアップ メニューが [AccountDocument 2] に設定されています。
2 つのモデルの唯一の違いは、1 つのエンティティに追加の (およびオプションの) 属性があることです。私の理解では、モデルが軽量の移行に適しているということです。
明らかに、私はここで何か間違ったことをしていますが、何がわかりません。どんな助けでも大歓迎です…</p>
アップデート:
Martin の提案 (および NSPersistentDocument ドキュメントのチェック) に従って、アクセサーに次のコードを使用してみました。
- (id)managedObjectModel
{
static id sharedManagedObjectModel = nil;
if (sharedManagedObjectModel == nil) {
NSBundle *bundle = [NSBundle mainBundle];
NSURL *url = [bundle URLForResource:@"AccountDocument2" withExtension:@"momd"];
sharedManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
}
return sharedManagedObjectModel;
}
まだクラッシュしています…</p>
アップデート
Twitter でいくつかの提案を受けて、Xcode 4.3.2 にアップグレードしましたが、問題は解決しません。
レイジアップデート
Snow Leopard で Xcode 4.2 を使用して、バージョン管理されたモデル パッケージ (AccountDocument2.xcdatamodeld) を作成しました。アプリをビルドして実行すると、すべてが期待どおりに機能します。
次に、AccountDocument2.xcdatamodeld ファイル パッケージを Lion と Xcode 4.3.2 に戻しました。アプリをビルドして実行すると、.momd リソースの読み込み中に引き続きクラッシュします。はい、子供たち、つまり、Xcode 4.3.x と Data Model Compiler (MOMC) のせいです。すべてのビルドを Snow Leopard で実行する以外に回避策がありません。
私は Xcode 4 をバッシングする人ではありませんが、ツールチェーンが不透明な仕様 (.xcdatamodel および .xcdatamodeld) から不透明なファイル (.mom および .momd) を生成できない状況に陥った場合、それを行うのはかなり困難です。 Mac と iOS ツールの状態について楽観的であること。これらのプラットフォームのコア コンポーネントが壊れて、最新バージョンの SDK と開発者ツールでアプリをビルドして実行できないというのはばかげています。
このアップデートに来ました
これが Xcode 4.3.2 の Data Model Compiler (MOMC) の重大なバグであることのさらなる証拠: Xcode 4.2 によって作成された Resource フォルダーから .momd バンドルをプロジェクトにコピーし、それらをビルドにコピー ファイルとして追加した場合ビルド段階で、アプリケーションは正常に動作します。
また、さまざまなエンティティの属性の検証ルールとデフォルト値を削除するいくつかのテストも行いました (以下のマーカスの提案に基づいています)。変更はありません。コンパイラは引き続き無効な .momd を作成します。また、何も変更されていないバージョン管理されたモデルを作成しようとしました。コンパイルされた .momd はクラッシュし続けました。したがって、現在のモデル (およびそれらが表すデータ) に含まれているものは何でも、問題の原因です。
また、注意してください:このバグは NSPersistentDocument に分離されていません(この質問を始めたときに最初に考えたように)[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]
.
今のところ、Snow Leopard で Xcode 4.2 を使用してモデルを編集/バージョン管理し、コンパイルされたリソースを Lion で Xcode 4.3.2 に移動します。Core Data を何らかの方法で使用する場合は、このバグが解決されるまで同じことを行うことをお勧めします。私を信じてください、あなたがしなければ一体何が起こっているのかを理解しようと何日も費やすでしょう.
レーダーを送信するには…</p>
レーダーの更新
このレーダーを送信しました:
http://www.openradar.me/11184500
The Oh Crap It Must Be Lion アップデート
http://developer.apple.com/downloadsから Lion ツール用の Xcode 4.2 をダウンロードしてインストールしました。Radar で使用されているサンプル アプリケーションは引き続きクラッシュします。
(注: DeveloperTools.pkg の署名に使用された証明書の有効期限が切れているため、Xcode 4.2.1 をインストールすることはできません。Xcode 4.2 のみが機能します。)
NDA を締結している場合は、ベータ ツールも役に立たないことがわかります。
Xcode 4.2 がインストールされた Snow Leopard のコピーがあることを願っています: http://furbo.org/2012/03/28/vmware-for-developers/
WTF Do Fetch リクエストは、バージョン管理されたエンティティと属性の更新に関係しています
TwitterのEvadne Wu経由:
https://twitter.com/#!/evadne/status/187625192342818818
そして彼女はどのようにそれをしたか:
https://twitter.com/#!/evadne/status/187629091518816258
(.mom ファイルはバイナリ plist です。)
問題の根本は、単一のフェッチ リクエストです。それが、あるモデルから別のモデルへのデータの移行にどのように影響するかは、Apple のエンジニアが把握する必要があります。