设置新谓词后 NSFetchedResultsController 未正确刷新

NSFetchedResultsController not refreshing properly after setting new predicate

我的 fetchedResultsController 最初是这样创建的(在 viewDidLoad 中):

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
                               entityForName:@"Cat" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                          initWithKey:@"age" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                    managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"age"
                                               cacheName:@"whatever"];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;

这很好用,结果显示在我的 table 视图中。但是,当按下某些按钮时,我想过滤结果。所以我这样做:

NSPredicate *predicate = ...; //based on buttons pressed


[[self.fetchedResultsController fetchRequest] setPredicate:predicate];
[NSFetchedResultsController deleteCacheWithName:@"whatever"];

NSError * error = nil;
[self.fetchedResultsController performFetch:&error];
if (error) {
    DDLogError(@"[%@ %@] fetchedResultsController ERROR: %@", THIS_FILE, THIS_METHOD, error.localizedDescription);
}
[self.myTableView reloadData];

问题是 table 视图没有重新加载。如果我滚动 table 视图,单元格会根据新数据发生变化,但每次我尝试过滤时,部分和行数都不会发生变化。

我错过了什么?

您需要在对 fetchResult 控制器进行任何更改之前删除缓存

来自苹果文档:NSFetchedResultsController Class Reference

If you are using a cache, you must call deleteCacheWithName: before changing any of the fetch request, its predicate, or its sort descriptors. You must not reuse the same fetched results controller for multiple queries unless you set the cacheName to nil.

Optionally, the name of the cache file the controller should use (passing nil prevents caching). Using a cache can avoid the overhead of computing the section and index information.

我怀疑您需要根据更新后的数据插入和删除 table 视图行。

您在对其他答案的评论中写的错误消息提供了线索。

相关Apple documentation

具体要看的是标题下的文字:行和节的批量插入、删除和重载.

然而,在此之前,当您更改 NSFetchedResultsController 时,您应该检查是否实现了 NSFetchedResultsController 委托方法来管理更改。 Apple 提供了标准代码,您应该考虑将其包含在 table 视图控制器中。您不需要更改/覆盖此标准代码。

看到这个 Apple documentation

本质上,对于 "Typical Use" 情况,您需要实现四种典型的委托方法:

  • (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;
  • (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo;
  • (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath;
  • (void)controllerDidChangeContent:(NSFetchedResultsController *)controller .

如果您已经包含了这些 NSFetchedResultsController 委托方法,您可能需要考虑使用 UITableView 委托方法 beginUpdatesendUpdates使用方法:

- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation: (UITableViewRowAnimation)animation;
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation: (UITableViewRowAnimation)animation;

因此您应该尝试使用以下代码块:

tableView.beginUpdates;
tableView.insertRowsAtIndexPaths:indexPaths withRowAnimation:animation;
tableView.deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation;
tableView.endUpdates

您显然需要为插入和删除方法创建索引路径数组。