2

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

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

这是我非常简单的 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 不要为不匹配的计数出汗?还是我需要完全不同的方法?

4

2 回答 2

8

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

呼吁!

于 2013-09-11T18:06:03.627 回答
2

Martin R 给出了很好的答案,但他忽略了一件重要的事情:

如果 FetchControllerProtocol 想要同时刷新很多行,它可能会崩溃。

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;
    }
}

希望这可以帮助

于 2015-05-07T09:37:59.020 回答