30

次のように 2 つのマネージド オブジェクト コンテキストが設定されたアプリがあります。

  • 親コンテキスト: 永続ストアにリンクされた NSPrivateQueueConcurrencyType。
  • メイン コンテキスト: NSMainQueueConcurrencyType、親コンテキストの子。

新しいマネージド オブジェクトをメイン コンテキストに挿入するときは、メイン コンテキストを保存してから、次のように親コンテキストを保存します。

[context performBlockAndWait:^{
    NSError * error = nil;
    if (![context save: &error]) {
        NSLog(@"Core Data save error %@, %@", error, [error userInfo]);
    }
}];

[parentContext performBlock:^{
    NSError *error = nil;
    BOOL result = [parentContext save: &error];
    if ( ! result ) {
        NSLog( @"Core Data save error in parent context %@, %@", error, [error userInfo] );
    }
}];

私の理解では、管理オブジェクトが最初に作成されたとき、一時的なobjectID. 次に、メイン コンテキストが保存され、一時 ID を持つこのオブジェクトが親コンテキストに到達します。次に、親コンテキストが保存されます。この最後のコンテキストが保存objectIDされると、親コンテキストの一時が永続に変換されobjectIDます。

そう:

  • 永続的なオブジェクト ID は、メイン (子) コンテキストに自動的に反映されますか?
  • でオブジェクトの永続 ID を強制的に取得し [NSManagedObjectContext obtainPermanentIDsForObjects:error:]、アプリをバックグラウンドで実行し、再アクティブ化し、リロードし、メイン コンテキストの を使用してオブジェクトを取得しobjectWithID:、プロパティにアクセスすると、次のようになります。

    「CoreData は ... の障害を実行できませんでした」.

このアプローチの何が問題なのですか?

4

3 に答える 3

43

これは既知のバグであり、すぐに修正されることを願っていますが、一般的に、最初の子にデータを保存する前に永続的な ID を取得し、挿入されたオブジェクトのみを含める場合は、永続的な ID を取得するだけで十分です。

[moc obtainPermanentIDsForObjects:moc.insertedObjects.allObjects error:&error]

複雑なケースでは、特に複雑な関係がある場合は、インスタンスを作成したらすぐに永久 ID を取得することをお勧めします。

いつ、どのように電話していますobtainPermanentIDsForObjectsか?

アプリのクラッシュに関する部分はフォローしません。たぶん、より良い説明が役立つでしょう。

于 2012-08-16T23:39:37.287 に答える
11

Jody が上で述べたように、子 ManagedObjectContext を使用してバックグラウンド スレッドで新しい NSManagedObject を作成する場合は、保存する前に次の操作を行って永続 ID を強制的に作成する必要があります。

NSError *error = nil;

[threadedMOC obtainPermanentIDsForObjects:threadedMOC.insertedObjects.allObjects error:&error];

BOOL success = [threadedMOC save:&error];

私見ですが、この方法で行うのはあまり直感的ではありません。結局のところ、保存する前に永続的な ID を求めているのです! しかし、これはそれが機能するように見える方法です。保存後にパーマネント ID を要求した場合、ID は引き続き一時的なものです。Apple Docs から、実際に以下を使用して、オブジェクトの ID が一時的なものかどうかを判断できます。

BOOL isTemporary = [[managedObject objectID] isTemporaryID];
于 2013-10-08T12:01:16.233 に答える
2

問題はまだ iOS 8.3 に存在します Swift のソリューション:

func saveContext(context: NSManagedObjectContext?){
   NSOperationQueue.mainQueue().addOperationWithBlock(){
    if let moc = context {
        var error : NSError? = nil
        if !moc.obtainPermanentIDsForObjects(Array(moc.insertedObjects), error: &error){
            println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)")
        }
        if moc.hasChanges && !moc.save(&error){
            println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)")
        }
    }
 }
}

func saveBackgroundContext(){
    saveContext(self.defaultContext)

    privateContext?.performBlock{
        var error : NSError? = nil
        if let context = self.privateContext {

            if context.hasChanges && !context.save(&error){
                println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)")
            }else {
                println("saved private context to disk")
            }
        }
    }
}

どこ:

  • defaultContext には concurrencyType .MainQueueConcurrencyType があります
  • privateContext には concurrencyType .PrivateQueueConcurrencyType があります
于 2015-04-22T20:47:06.500 に答える