Objective c 如何刷新NSFetchedResultsController?
我有一个NSFetchedResultsController,它在UITableView中显示数据。在选择创建核心数据项目时,我使用的是Xcode提供的boiler plate代码。我在NSFetchedResultsController使用的NSFetchRequest中添加了以下谓词(在初始化NSFetchedResultsController之前): 现在,在我的应用程序的另一个位置,我像这样设置了deleted属性(伪代码): 当我返回TableViewController时,它仍然显示此“已删除”行 当我尝试重新加载表视图时,什么也没有发生 当我尝试使用Objective c 如何刷新NSFetchedResultsController?,objective-c,cocoa-touch,core-data,nsfetchedresultscontroller,nspredicate,Objective C,Cocoa Touch,Core Data,Nsfetchedresultscontroller,Nspredicate,我有一个NSFetchedResultsController,它在UITableView中显示数据。在选择创建核心数据项目时,我使用的是Xcode提供的boiler plate代码。我在NSFetchedResultsController使用的NSFetchRequest中添加了以下谓词(在初始化NSFetchedResultsController之前): 现在,在我的应用程序的另一个位置,我像这样设置了deleted属性(伪代码): 当我返回TableViewController时,它仍然显示
performFetch
重新加载fetchedResultsController时,它会显示:
'致命错误:节信息的永久缓存与当前配置不匹配。您在未禁用缓存或使用+deleteCacheWithName:'的情况下非法变异了NSFetchedResultsController的获取请求、其谓词或其排序描述符
如果我删除缓存,在init方法中,调用performFetch
,然后调用[myTable reloadData]
它会工作
难道没有更简单的方法来刷新数据吗?最好使用NSFetchedResultsController的缓存功能
据我所知,我修改fetch请求、谓词或排序描述符的唯一位置是allocs和inits NSFetchedResultsController的同一个方法,因此它显示的错误消息似乎不正确
更新:现在我对NSFetchedResultsController
有了更好的理解,我知道它不会自动删除行,主要负责删除行的是controller:didChangeObject:atIndexPath:forChangeType:nowIndexPath:
方法。我实现了这个方法,因为我在我的项目中使用了苹果的模板
但是,在我的例子中,我并没有实际删除某个项目,我只是更新一个属性(deleted
),以指定该项目不应再存在于列表中。这意味着controller:didChangeObject:atIndexPath:forChangeType:nowIndexPath:
方法的更改类型是NSFetchedResultsChangeUpdate
而不是NSFetchedResultsChangeDelete
。我将代码更新为以下内容:
case NSFetchedResultsChangeUpdate: {
MyObj *obj = (MyObj *)anObject;
if (obj.deletedValue) { // NOTE: deletedValue returns the deleted property as BOOL
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else {
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
}
}
问题是我收到了错误消息:
无效更新:节0中的行数无效。更新(3)后现有节中包含的行数必须等于更新(3)前该节中包含的行数,加上或减去从该节中插入或删除的行数(1插入,2删除)。带userInfo(空)
基本上,它抱怨NSFetchedResultsController中的对象数和表中的单元格数不同步
希望这能让事情变得更清楚:
// DB Items (Name, Deleted):
[Foo, NO]
[Bar, NO]
[Baz, NO]
// mark one as deleted
Objects[1].deletedValue = YES;
// DB items now look like so:
[Foo, NO]
[Bar, YES]
[Baz, NO]
即使NSFetchedResultsController的NSFetchRequest的NSPreditate设置为deleted==NO
,NSFetchedResultsController仍会看到3个项目,而不是2个
我如何解决这个问题?我是否需要以某种方式刷新NSFetchedReutsController?还有什么问题?从错误消息中,我似乎很清楚,NSFetchedResultsController不希望您在创建它之后更改它的获取请求
您需要做的是在初始化
NSFetchedRequestController
之前将谓词添加到fetch请求中。如果要在应用程序运行时更改提取请求的谓词,可能需要创建一个新的NSFetchedRequestController并完全替换旧的控制器。您需要设置对NSFetchedRequestController的委托,以便跟踪更改。要处理批更新,您需要覆盖三种方法:
controllerWillChangeContent:
-(此处设置索引路径列表)
controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:
-(在此处存储每个调用)
controllerDidChangeContent:
(此处执行对UITableView的更新。)
对于更简单的情况,如果您知道每次只更新一行,请执行以下操作:
-(void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath;
{
switch (type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeUpdate:
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
问题是我没有意识到在这种情况下,deleted
是一个保留字。我不得不重命名该字段,它工作正常。我更新了问题,以澄清NSPredicate是在初始化NSFetchedRequestController之前添加的。我已经实现了此方法,因为我使用的是苹果的模板。不过,我应该更明确地说明这一点。我更新了这个问题,希望它更容易理解。很抱歉很晚才回复。是否在背景线程中将对象标记为已删除?在这种情况下,您还需要合并主线程的托管对象上下文上的更改。太糟糕了,我只能这样做!有一个确切的问题。以前的财产名称被“删除”;在更改为“隐藏”后,FRC将触发相应的更新。我遇到了完全相同的问题。天哪,多可怕的虫子啊。文档中的保留字在哪里?谢谢你的修复。太棒了。。。我也有同样的问题。你到底是怎么知道“删除”是一个关键词的?我也面临着同样的问题,尽管我没有使用过像“删除”这样的保留词。还有其他的可能性吗?
// DB Items (Name, Deleted):
[Foo, NO]
[Bar, NO]
[Baz, NO]
// mark one as deleted
Objects[1].deletedValue = YES;
// DB items now look like so:
[Foo, NO]
[Bar, YES]
[Baz, NO]
-(void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath;
{
switch (type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeUpdate:
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}