0

私のアプリは、コアデータを使用していくつかのユーザー情報(名前、生年月日、サムネイルなど)を追加するだけです。

ユーザーを作成した直後に削除すると、アプリが機能しなくなることに気付きました(クラッシュではなく、xCodeはクラッシュログを返さず、何も返しません)。

ユーザー情報を保存するために非同期のネストされたコンテキストを使用しているので、動作はdeleteステートメントがステートメントの前に実行されているためだと思いsaveます。

しかし、私はCore Dataの初心者なので、それを処理する方法がよくわかりません。ネストされたコンテキストを正しい方法で宣言したかどうかさえわかりません。

これが私のsaveコードです:

NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    tmpContext.parentContext = self.backgroundManagedObjectContext;

    BSStudent *newStudent = (BSStudent *)[NSEntityDescription insertNewObjectForEntityForName:kBSStudent inManagedObjectContext:tmpContext];

    newStudent.firstname = firstname;
    newStudent.lastname = lastname;
    newStudent.birthdate = birthdate;
    newStudent.thumbnail = thumbnail;
    newStudent.createdAt = [NSDate date];

    [self dismissViewControllerAnimated:YES completion:nil];

    [tmpContext performBlock:^{
        [tmpContext save:nil];

        [self.backgroundManagedObjectContext performBlock:^{
            NSError *error;
            if (![self.backgroundManagedObjectContext save:&error]) {
                NSLog(@"%@", [error localizedDescription]);
            }

            [self.managedObjectContext performBlock:^{
                NSError *error;
                if (![self.managedObjectContext save:&error]) {
                    NSLog(@"%@", [error localizedDescription]);
                }
            }];
        }];
    }];

精度のために、self.managedObjectContextはaNSPrivateQueueConcurrencyTypeであり、self.backgroundManagedObjectContextNSMainQueueConcurrencyTypeです。そしてself.backgroundManagedObjectの子ですself.managedObjectContext

これが私の削除コードです:

    BSStudent *student = objc_getAssociatedObject(alertView, kDeleteStudentAlertAssociatedKey);

    // on supprimer l'objet et on sauvegarde le contexte
    [self.managedObjectContext deleteObject:student];
    NSError *error;
    if(![self.managedObjectContext save:&error]) {
        NSLog(@"%@", [error localizedDescription]);
    }

誰かがこの状況を適切に処理する方法を知ることができますか?

4

2 に答える 2

4

削除は、削除元とはBSStudent異なるコンテキストで作成されたものを使用している可能性があります。次のコードはそれを修正します。

NSManagedObjectContext * deleteContext = student.managedObjectContext;
[deleteContext deleteObject:student];

本当に他のコンテキストを使用したい場合は、ObjectIDを使用して学生を再フェッチします

NSManagedObject * studentToDelete = [self.managedObjectContext objectWithID:student.objectID];
[self.managedObjectContext deleteObject:studentToDelete];

ネストされたコンテキストのヒント

あなたのコンテキストはおそらく大丈夫ですが、多くの人が不必要にperformBlockを投げ回しているのを目にします。ネストされたコンテキストでは、QueueConcurrencyTypeは、作成されたスレッドではなく、CoreData操作を実行するスレッドを参照します。したがって、performBlock内でそれ自体を保存するような操作を行うことは不要であり、デッドロックにつながる可能性があります。

子コンテキストを保存すると、親は変更と自動的に同期されます。次に上位の親に自動的に上向きに保存する場合は、子の保存のNSManagedObjectContextDidSaveNotificationに親を登録することをお勧めします。AppDelegateに子コンテキストを作成するためのファクトリメソッドを持たせることで、これを簡単に行うことができます。

- (NSManagedObjectContext *)createChildContext
{
    NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    tmpContext.parentContext = self.managedObjectContext;
    //Register for NSManagedObjectContextDidSaveNotification
    return tmpContext;
}
于 2013-01-27T01:22:11.353 に答える
1

呼び出しで削除をラップするperformBlockと、保存と同時に実行できませんperformBlock

例えば:

BSStudent *student = objc_getAssociatedObject(alertView, kDeleteStudentAlertAssociatedKey);

// on supprimer l'objet et on sauvegarde le contexte
[self.managedObjectContext performBlock:^{
    [self.managedObjectContext deleteObject:student];
    NSError *error;
    if(![self.managedObjectContext save:&error]) {
        NSLog(@"%@", [error localizedDescription]);
    }
}];

これは、コンテキストへのアクセスをシリアル化し、すべての操作をコンテキスト スレッドに保持するため、コンテキストを処理する「推奨される」方法です。

objectID が無効になるか、保存が完了する前に変更されるため、クラッシュが発生していると思います。呼び出しスタックの上部近くに、「hash64」などに関する何かが表示されます。

于 2013-01-27T12:50:29.800 に答える