Ios NSFetchedResultsController具有筛选NSPredicate的didChangeObject

Ios NSFetchedResultsController具有筛选NSPredicate的didChangeObject,ios,objective-c,uitableview,core-data,nsfetchedresultscontroller,Ios,Objective C,Uitableview,Core Data,Nsfetchedresultscontroller,我有一个由NSFetchedResultsController支持的UITableView,它显示用户已添加书签的项目。可以通过行中的按钮取消对项目的书签,这会导致问题。取消项目书签后,它应该会从表视图中消失,因为它不再匹配谓词,但由于更新更改了我的每个节的行数,我得到了此错误的一个变体: CoreData:错误:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从委托NSFetchedResultsController捕获到异常。无效更新:无效 节0中的行

我有一个由NSFetchedResultsController支持的UITableView,它显示用户已添加书签的项目。可以通过行中的按钮取消对项目的书签,这会导致问题。取消项目书签后,它应该会从表视图中消失,因为它不再匹配谓词,但由于更新更改了我的每个节的行数,我得到了此错误的一个变体:

CoreData:错误:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从委托NSFetchedResultsController捕获到异常。无效更新:无效 节0中的行数。更新后现有节中包含的行数(3) 必须等于更新之前该节中包含的行数(4),加上或减去 从该节插入或删除的行数(0插入,0删除)加上或减去 移入或移出该节的行数(0移入,0移出)。带userInfo(空)

下面是我非常简单的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不要忽略不匹配的计数?或者我需要完全不同的方法吗?

您的
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];

这是我的电话

马丁·R给出了很好的回答,但他忽略了一件重要的事情:

如果FetchControllerProtocol希望同时刷新许多行,它可能会崩溃

给出一个非常清晰的典型过程示例。使用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;
    }
}
-(void)控制器:(NSFetchedResultsController*)控制器didChangeSection:(id)sectionInfo
atIndex:(nsInteger)ChangeType:(NSFetchedResultsChangeType)类型的节索引{
开关(类型){
案例NSFetchedResultsChangesInsert:
[self.tableView insertSections:[NSIndexSet IndexSetWithiIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
打破
案例NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet IndexSetWithiIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
打破
}
}

希望这有帮助

谢谢Martin。我没有处理所有这些情况的原因是,
NSFetchedResultsChangeUpdate
是我的应用程序中触发的唯一更改类型。之所以调用super,是因为我实现此方法的类是类层次结构的一部分,但我同意这在某种程度上混淆了问题。我将更新帖子以使用您更标准的代码,因为问题仍然存在。@Dane:但是如果某个项目“未添加书签”,并且不再与谓词匹配,则将使用
NSFetchedResultsChangeDelete
事件调用
didChangeObject
。您真的应该实现完整的委托方法!啊,我明白了,这可能就是问题所在@Dane:您是否也实现了
controller:didChangeSection:atIndex:forChangeType: