NSFetchedResultsController:删除1行使应用程序崩溃

时间:2014-01-19 21:22:24

标签: ios uitableview core-data nsfetchedresultscontroller

从NSFetchedResultsController提供的UITableView中删除行会导致我的应用程序崩溃。

错误是:

  

*断言失败 - [UITableView _endCellAnimationsWithContext:],/ SourceCache / UIKit / UIKit-2903.23 / UITableView.m:1330
  *
由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:第0节中的行数无效。更新后的现有部分中包含的行数(1)必须等于数字在更新(1)之前该部分中包含的行,加上或减去从该部分插入或删除的行数(插入0,删除1),加上或减去移入或移出该部分的行数(0)搬进来,0搬出去。'

我只想滑动删除。我的删除代码如下:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{  
    [self.tableView beginUpdates];  
    SequenceData *sd = [self.fetchedResultsController objectAtIndexPath:indexPath];  
    [self.managedObjectContext deleteObject:sd];  
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                          withRowAnimation:UITableViewRowAnimationFade];  
    [self.tableView endUpdates];  
}

我的NSFetchedResultsController的设置就像Ray Wanderlich的教程(http://www.raywenderlich.com/999/core-data-tutorial-for-ios-how-to-use-nsfetchedresultscontroller

行数由:

决定
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    
    id sectionObjects = [[self.fetchedResultsController sections] objectAtIndex:section];  
    NSInteger nbObjects = [sectionObjects numberOfObjects];  
    return nbObjects;  
}

看起来fetch没有更新(行数不变)。我是否需要取自己(这不是由fetch控制器处理)?

这里显然有一些基本的东西。不要犹豫,建议基本答案。

我首先用控制器实现了这个:didChangeObject:...方法。错误是一样的,但有些细节不同。

修改 我相信我的问题是固定的。这两个答案(来自CX和Martin)帮助我找到了答案。马丁得到了答案,因为解释有助于我更好地理解......

2 个答案:

答案 0 :(得分:12)

不要打电话

[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

如果使用获取的结果控制器。仅使用

删除对象
[self.managedObjectContext deleteObject:sd];

然后自动调用获取的结果控制器委托方法 didChangeObject:, 并且调用deleteRowsAtIndexPaths:

因此,在您的情况下,该行被删除了两次,这导致了异常。

请注意,此处不需要beginUpdates / endUpdates

答案 1 :(得分:4)

如果要删除行,则只需删除managedObject。

if (editingStyle == UITableViewCellEditingStyleDelete)
{
    [self.managedObjectContext deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];

    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        // handle error
    }
}

删除托管对象会触发NSFetchResultController委托方法,并会更新tableView

修改

您应该实现NSFetchResultController委托方法

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath{
switch(type) {
 case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
}


////
   default:
   break;
    }

因为当您使用NSFetchedResultsController等数据源时,所有更改都必须来自那里,而您的表只反映它们。