设置新谓词后 NSFetchedResultsController 未正确刷新
Posted
技术标签:
【中文标题】设置新谓词后 NSFetchedResultsController 未正确刷新【英文标题】:NSFetchedResultsController not refreshing properly after setting new predicate 【发布时间】:2015-09-16 21:36:17 【问题描述】:我的 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;
这很好用,结果显示在我的表格视图中。但是,当按下某些按钮时,我想过滤结果。所以我这样做:
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];
问题是表格视图没有重新加载。如果我滚动表格视图,单元格会根据新数据发生变化,但每次尝试过滤时,节数和行数不会发生变化。
我错过了什么?
【问题讨论】:
您应该使用 cmets 中的错误消息将您的问题更新为其他答案。 【参考方案1】:您需要在对 fetchResultController 进行任何更改之前删除缓存
来自苹果文档:NSFetchedResultsController Class Reference
如果你使用缓存,你必须调用 deleteCacheWithName: 之前 更改任何获取请求、其谓词或排序 描述符。您不得重复使用相同的提取结果控制器 对于多个查询,除非您将 cacheName 设置为 nil。
(可选)控制器应使用的缓存文件的名称 (传递 nil 可防止缓存)。使用缓存可以避免开销 计算节和索引信息。
【讨论】:
感谢您的建议。不幸的是,它并没有改变任何东西。出于某种原因,即使获取的对象的数量确实得到了更新,tableView 也不会重新加载。例如,我将从表中的 4 个部分开始,但过滤后 fetchedResultsController 中将只有 3 个对象,因此如果我尝试滚动表,我将收到 NSRangeException 崩溃。 [__NSArrayM objectAtIndex:]: 索引 3 超出范围 [0 .. 2] 因为您需要更改谓词,所以最好将 cacheName 设置为 nil。没有看到缓存为零使 fecthResultController 保留节号和行号【参考方案2】:我怀疑您需要根据更新的数据插入和删除表视图行。
您在 cmets 中写给另一个答案的错误消息包含了线索。
相关Apple documentation。
您应该特别阅读的是标题下的文字:行和节的批量插入、删除和重新加载。
然而,在此之前,当您更改 NSFetchedResultsController
时,您应该检查您是否实现了 NSFetchedResultsController 委托方法来管理更改。 Apple 提供了标准代码,您应该考虑将其包含在表视图控制器中。您不需要更改/覆盖此标准代码。
看到这个Apple documentation。
对于“典型用例”,您需要实现四种典型的委托方法:
(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 委托方法 beginUpdates
和 endUpdates
与方法一起使用:
- (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
您显然需要为 insert 和 delete 方法创建 indexPaths 数组。
【讨论】:
以上是关于设置新谓词后 NSFetchedResultsController 未正确刷新的主要内容,如果未能解决你的问题,请参考以下文章
具有核心数据关系的 iOS 8 Swift NSFetchResult 谓词无法访问内部 ID