如何刷新NSFetchedResultsController?

问题描述:

我有一个NSFetchedResultsController在UITableView中显示数据。在选择创建Core Data项目时,我使用Xcode提供的锅炉代码。我添加了以下谓词到NSFetchRequest的NSFetchedResultsController使用(NSFetchedResultsController初始化之前):在我的应用程序的另一个位置如何刷新NSFetchedResultsController?

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"deleted == NO"]; 
[fetchRequest setPredicate:predicate]; 

现在,我设置的已删除属性,像这样(伪代码):

myManagedObject.deleted = YES 
saveDataContext 

当我返回到TableViewController时,它仍然显示这个“删除”行。

当我尝试重新加载表视图时,没有任何反应。

当我尝试使用performFetch重新加载fetchedResultsController,它说:

'FATAL ERROR: The persistent cache of section information does not match the current configuration. You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:'

如果我删除缓存,在init方法,调用performFetch,然后调用[myTable reloadData]它的工作原理。

是否有更简单的方法来刷新数据?最好能让你使用NSFetchedResultsController的缓存功能?

据我所知,我修改提取请求,谓词或排序描述符的唯一地方是在分配和注入NSFetchedResultsController的同一个方法中,所以看起来它显示的错误信息是不正确的。

更新:现在我明白了NSFetchedResultsController好一点,据我所知,它不会自动为您删除行,并且它的controller:didChangeObject:atIndexPath:forChangeType:nowIndexPath:方法是删除行主要负责人。我使用了这个方法,因为我的项目使用了Apple的模板。

但是,在我的情况下,我并没有真正删除一个项目,我只是更新一个属性(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; 
    } 
    } 

的问题,这是我得到的错误信息:

Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (1 inserted, 2 deleted). with userInfo (null)

基本上它的抱怨,在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的NSPredicate设置为deleted == NO,在NSFetchedResultsController仍然认为3项,而不是2

我怎样才能解决这个问题呢?我需要刷新NSFetchedReultsController吗?还有什么可能是这个问题?

的问题是,我并没有意识到deleted在这种情况下的保留字。我不得不重新命名该领域,它运作良好。

+1

太糟糕了,我只能做一个像! – 2012-06-13 10:08:32

+0

有这个确切的问题。先前的属性名称被“删除”;在更改为“隐藏”后,FRC将触发适当的更新。 – 2012-12-20 17:26:09

+0

我有完全相同的问题。神圣的废话,多么可怕的错误。这是文档中的保留字吗?感谢您的修复。 – 2013-09-09 22:46:09

从错误消息看来,我似乎很清楚,NSFetchedResultsController并不希望您在创建后更改其获取请求。

您需要做的是在NSFetchedRequestController被初始化之前将谓词添加到获取请求中。如果要在应用程序运行时更改提取请求的谓词,则可能需要创建一个新的NSFetchedRequestController并完全替换旧的。

+0

我更新了问题,以澄清在NSFetchedRequestController初始化之前添加了NSPredicate。 – Senseful 2010-10-06 15:51:52

+0

好吧。 – JeremyP 2010-10-06 16:17:08

您需要设置一个委托给NSFetchedRequestController以跟踪更改。为了处理批量更新,你需要重写三种方法:

  • controllerWillChangeContent: - (这里的索引路径设置列表)
  • controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: - (存储在这里的每个呼叫)
  • controllerDidChangeContent:(EXCUTE更新到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; 
    } 
} 
+0

我已经实现了这个方法,因为我使用的是Apple的模板。不过,我应该更明确地表述它。我更新了这个问题,希望能更容易理解。 – Senseful 2010-10-06 23:17:25

+0

对不起,很晚回复。你是否将这些对象标记为在后台线程上被删除?在这种情况下,您还需要合并主线程的托管对象上下文中的更改。 – PeyloW 2010-10-23 12:51:23