Objective c 如何刷新NSFetchedResultsController?

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时,它仍然显示

我有一个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;
    }
}