尝试保存NSManagedObject时崩溃

时间:2014-11-25 19:58:24

标签: ios objective-c core-data nsmanagedobject nsmanagedobjectcontext

美好的一天,大家!

我有一个UITableView。我需要添加一些对象(有一些属性,在这种情况下,我至少需要名称),当我在导航栏中点击“+”时,新的UIViewController以模态方式呈现,而在viewDidLoad我调用此方法,设置默认名称它:

- (void)createManagedObject {

    NSManagedObjectContext *context = [[DVCoreDataManager sharedManager] managedObjectContext];
    NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"DVObject" inManagedObjectContext:context];

    [newManagedObject setValue:@"new object" forKey:@"name"];

    NSError *error = nil;
    if (![context save:&error]) {
        NSLog(@"%@", [error localizedDescription]);
    }

    self.currentObjectID = newManagedObject.objectID;
}

在UITextField中输入名称后,我点击“保存”按钮并调用该方法,我需要更新对象的名称:

- (IBAction)actionSaveTraining:(UIBarButtonItem *)sender {

    NSManagedObjectContext *context = [[DVCoreDataManager sharedManager] managedObjectContext];
    NSManagedObject *newManagedObject = [context existingObjectWithID:self.currentObjectID error:nil];

    [newManagedObject setValue:self.nameTextField.text forKey:@"name"];

    NSError *error = nil;
    if (![context save:&error]) {
        NSLog(@"%@", [error localizedDescription]);
    }

    [self dismissViewControllerAnimated:YES completion:nil];
}

此时应用程序因错误而崩溃:

  

***由于未捕获的异常'NSInternalInconsistencyException'而终止应用,原因:'无效更新:无效   第0节中的行数。包含在中的行数   更新后的现有部分(7)必须等于数量   更新前的该部分中包含的行(7),加号或减号   从该部分插入或删除的行数(插入0,   删除1)加上或减去移入或移出的行数   该部分(0移入,0移出)。'

我已经实现了NSFetchedResultsControllerDelegate方法。 controllerDidChangeContent:在createManagedObject方法之后调用,但 controllerWillChangeContext:从未被调用,我无法理解为什么。

- (void)controllerWillChangeContext:(NSFetchedResultsController *)controller {

    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeMove:
            break;

        case NSFetchedResultsChangeUpdate:
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeUpdate:    
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        default:
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

    [self.tableView endUpdates];
}

如何解决此错误?也许有更好的方法来做我需要的事情? (在创建时设置默认名称,保存时,从uitextfield设置名称)

2 个答案:

答案 0 :(得分:1)

您输入的controllerWillChangeContent方法名称不正确:最后一个字应为内容而非上下文

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {

    [self.tableView beginUpdates];
}

答案 1 :(得分:0)

关于更好的方法的评论,我看到你有一个刚刚创建的对象managedObjectID的属性。您是否有任何理由不仅拥有托管对象本身的属性?创建新对象后,您将其分配给您的本地属性。然后当你更新它时,你只需要调用

[self.newObject setValue:self.nameTextField.text forKey:@"name"];

然后像你已经做的那样保存(只要你在方法[[DVCoreDataManager sharedManager] managedObjectContext]中提供的上下文是NSMainQueueConcurrencyType类型。如果它是一个背景上下文,你需要包装两个那些-performBlock:performBlockAndWait:)。

这也假设从呈现的viewController中获取的结果控制器使用与新对象viewController相同的NSManagedObjectContext