带有过滤 NSPredicate 的 NSFetchedResultsController didChangeObject
Posted
技术标签:
【中文标题】带有过滤 NSPredicate 的 NSFetchedResultsController didChangeObject【英文标题】:NSFetchedResultsController didChangeObject with a filtering NSPredicate 【发布时间】:2013-09-11 17:57:00 【问题描述】:我有一个由 NSFetchedResultsController 支持的 UITableView,它显示用户已添加书签的项目。可以从行中的按钮取消对项目的书签,这会导致问题。取消标记某个项目后,它应该从表视图中消失,因为它不再与谓词匹配,但是因为我每节的行数已被更新更改,我得到了这个错误的变体:
CoreData:错误:严重的应用程序错误。在调用 -controllerDidChangeContent: 期间,从委托 NSFetchedResultsController 中捕获了异常。无效更新:无效 第 0 节中的行数。更新后现有节中包含的行数 (3) 必须等于更新前该节中包含的行数 (4),加上或减去 从该部分插入或删除的行数(0 插入,0 删除)加上或减去 移入或移出该部分的行数(0移入,0移出)。与 userInfo (null)
这是我非常简单的 didChangeObject 方法:
-(void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
[super controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:type newIndexPath:newIndexPath];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
有什么方法可以指示 NSFetchedResultsController 不要为不匹配的计数出汗吗?还是我需要完全不同的方法?
【问题讨论】:
【参考方案1】:您的didChangeObject
委托方法看起来很不完整,
特别是它不检查发生了哪个事件(插入、删除或更新)。
您可以在NSFetchedResultsControllerDelegate
协议中找到模板
文档。
该方法通常看起来与此类似:
- (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:
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
您还应该实现controller:didChangeSection:atIndex:forChangeType:
委托方法。
我不明白是什么
[super controller:controller didChangeObject:anObject atIndexPath:indexPath forChangeType:type newIndexPath:newIndexPath];
呼吁!
【讨论】:
谢谢马丁。我不处理所有这些情况的原因是NSFetchedResultsChangeUpdate
是我的应用程序中唯一触发的更改类型。
对 super 的调用在那里是因为我实现此方法的类是类层次结构的一部分,但我同意它有点混淆了这个问题。我将更新帖子以使用您更标准的代码,因为问题仍然存在。
@Dane:但是如果一个项目是“未添加书签”并且不再匹配谓词,didChangeObject
将被调用 NSFetchedResultsChangeDelete
事件。你真的应该实现完整的委托方法!
啊,我明白了,这可能是问题所在!
@Dane:你也实现了controller:didChangeSection:atIndex:forChangeType:
吗?【参考方案2】:
Martin R 给出了很好的答案,但他忽略了一件重要的事情:
如果 FetchControllerProtocol 想要同时刷新很多行,它可能会崩溃。
The Apple Doc给出了一个非常清晰的典型流程示例。用 beginUpdates 和 endUpdates 方法包围您的表更改非常重要。
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
[self.tableView beginUpdates];
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
[self.tableView endUpdates];
如果您有部分,您还应该实现部分刷新
- (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:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
希望对你有帮助
【讨论】:
以上是关于带有过滤 NSPredicate 的 NSFetchedResultsController didChangeObject的主要内容,如果未能解决你的问题,请参考以下文章
带有过滤 NSPredicate 的 NSFetchedResultsController didChangeObject
带有数组的 nsdictionary nspredicate 过滤