代码之家  ›  专栏  ›  技术社区  ›  Dane

NSFetchedResultsController使用筛选NSPredcate didChangeObject

  •  2
  • Dane  · 技术社区  · 12 年前

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

    CoreData:错误:严重的应用程序错误。在调用-controllerIdChangeContent:期间,从代理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不要为不匹配的计数流汗?还是我需要一种完全不同的方法?

    2 回复  |  直到 12 年前
        1
  •  8
  •   Martin R    12 年前

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

    呼叫是为了!

        2
  •  2
  •   Martin    11 年前

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

    希望这能有所帮助