使用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:willChangeContent
和controller: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
刷新自己和表。