ios - 核心数据 - 如果在保存完成之前删除,应用程序崩溃

时间:2013-01-27 00:28:32

标签: ios core-data asynchronous crash nested

我的应用只是使用Core Data添加一些用户信息(名称,生日,缩略图......)。

我注意到如果我在创建后立即删除用户,我的应用程序就会停止工作(不是崩溃,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.managedObjectContextNSPrivateQueueConcurrencyTypeself.backgroundManagedObjectContextNSMainQueueConcurrencyTypeself.backgroundManagedObjectself.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]);
    }

有人知道如何妥善处理这种情况吗?

2 个答案:

答案 0 :(得分:4)

您的删除可能是使用由您删除的上下文创建的BSStudent。以下代码将解决这个问题。

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

如果您确实想使用其他上下文,请使用ObjectID

重新学习该学生
NSManagedObject * studentToDelete = [self.managedObjectContext objectWithID:student.objectID];
[self.managedObjectContext deleteObject:studentToDelete];

嵌套上下文提示

你的上下文可能还可以,但我看到很多人不必要地抛出performBlock。对于嵌套的上下文,QueueConcurrencyType引用它将对其进行核心数据操作的线程,而不是它在其上创建的线程。因此,在performBlock中执行像保存一样的操作是不必要的,并且可能导致死锁。

保存子上下文时,父级会自动与更改同步。如果您想自动向上保存到下一个更高的父级,我建议为子级保存的NSManagedObjectContextDidSaveNotification注册父级。通过让AppDelegate具有用于创建子上下文的工厂方法,可以使这更容易。

- (NSManagedObjectContext *)createChildContext
{
    NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    tmpContext.parentContext = self.managedObjectContext;
    //Register for NSManagedObjectContextDidSaveNotification
    return tmpContext;
}

答案 1 :(得分:1)

如果您在performBlock调用中包含删除内容,则无法在保存performBlock的同时执行。

e.g:

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”或类似内容的内容