使用fetchedResultController删除表视图中的行

在swype删除(这种方法的最重要的行):

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { Table *deleteRow = [self.fetchedResultsController objectAtIndexPath:indexPath]; [self.managedObjectContext deleteObject:deleteRow]; [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } 

当删除行时,我得到这个错误:

由于未捕获exception“NSInternalInconsistencyException”而终止应用程序,原因是:“无效更新:第2节中的行数无效。
更新(1)之后,现有节中包含的行数必须等于更新前(1)节中包含的行数加上或减去从该节插入或删除的行数(插入0 ,1删除),加上或减去移入或移出该部分的行数(移入0,移出0)。

如果我注释的最后一行代码( [tableView deleteRowsAtIndexPaths:...] )一切工作正常(但我必须刷新视图,看看那行被删除)。

如何正确地做到..?

编辑:考虑@Kyr Dunenkoff响应我补充说:

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

但是这并没有改变崩溃和错误。 Atm只是造成添加新行不再工作。

为了做到这一点,实现controller:didChangeObject:方法,在其内为不同的变化types,在NSFetchedResultsChangeDelete情况下插入您的[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 。 因为当你使用像NSFetchedResultsController这样的数据源时,所有的改变都必须来自那里,你的表只反映它们。 此外,您可以实现controller:willChangeContentcontroller:didChangeContent ,将[tableView beginUpdates]放入到willChange[tableView endUpdates]放入didChange

问题是 – 正如你通过评论发现的 – 你的最后一行:

 [tableView deleteRowsAtIndexPaths:... 

苹果表视图编程指南告诉你需要这样做,但实际上你不应该在使用NSFetchedResultsController时。 NSFetchedResultsController的想法是, 负责更新UI以保持与模型同步,所以你不需要。 因此,如果您只是从模型中删除对象,则获取的结果控制器将负责处理其余部分。

[更新]哎呀,不完全正确的,我刚才说的。 在没有任何帮助的情况下,获取的结果控制器将不仅仅是“照顾其他人”。 这是委托将其余的照顾,但有人需要执行它的委托。 我养成了Standford CS193p课程的CoreDataTablewViewController帮助器类的习惯,它只是一个UITableViewController子类,它实现了NSFetchedResultsController文档中推荐的所有方法。 最重要的是,它实现了模型更改时更新表视图的委托方法。

所以你的更新的方法仍然是正确的:你不应该把deleteRowsAtIndexPaths ..放在导致用户删除它们的代码中,而是让获取的结果控制器驱动进程,并实现委托来实际执行它。

(在这里获得助手类: http : //www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2011-fall ,并观看第14讲,看看如何使用它)

Kyr的答案是正确的,但是这里是一个离散的例子,说明如何从数据库以及从NSFetchedResultsController中删除NSManagedObject:

 - (void) deleteObjectFromDBAndTable:(NSIndexPath *)indexPath forTable:(UITableView*)tableView { NSLog(@"Deleting object at row %d", indexPath.row); // Delete the object from the data source NSManagedObject *objToDelete = (NSManagedObject*)[self.fetchedResultsController objectAtIndexPath:indexPath]; // Delete the object from the database [DBHandler deleteObject:objToDelete andSave:YES]; } - (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; } } 

你需要确保你不要调用[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 你自己。 从上下文中删除对象将触发NSFetchedResultsController刷新自己和表。