代码之家  ›  专栏  ›  技术社区  ›  Senseful

如何刷新nsfetchedresultsController?

  •  2
  • Senseful  · 技术社区  · 14 年前

    我有一个nsfetchedresultsController,它在一个UITableView中显示数据。我正在使用xcode提供的锅炉板代码来创建核心数据项目。我在nsfetchedResultsController使用的nsfetchRequest中添加了以下谓词(在nsfetchedResultsController初始化之前):

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

    现在在我的应用程序的另一个位置,我将删除的属性设置为so(伪代码):

    myManagedObject.deleted = YES
    saveDataContext
    

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

    当我尝试重新加载表视图时,什么也不会发生。

    当我尝试重新加载提取结果控制器时, performFetch 它说:

    '致命错误:节信息的持久缓存与当前配置不匹配。您非法改变了nsfetchedresultsController的提取请求、谓词或排序描述符,但没有禁用缓存或使用+deletecacheWithName:'

    如果移除缓存,在init方法中,调用 执行取回 然后调用 [myTable reloadData] 它起作用了。

    有没有更简单的方法来刷新数据?最好使用nsfetchedresultsController的缓存功能?

    据我所知,我修改FETCH请求、谓词或排序描述符的唯一地方与分配和初始化nsfetchedResultsController的方法相同,因此它显示的错误消息似乎不正确。

    更新: 现在我明白了 NSFetchedResultsController 好一点,我知道它不会自动为您删除行,这是 controller:didChangeObject:atIndexPath:forChangeType:nowIndexPath: 主要负责删除行的方法。我已经实现了这个方法,因为我在我的项目中使用了苹果的模板。

    但是,在我的例子中,我并没有真正删除一个项目,我只是更新一个属性( deleted )指定该项不再存在于列表中。这意味着 控制器: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行)。带用户信息(空)

    基本上,它抱怨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]
    

    即使nsfetchedresults控制器的nsfetchrequest的nspredicate设置为 deleted == NO ,nsvectedResultsController仍然看到3项而不是2项。

    我如何解决这个问题?我需要刷新nsfectedReultsController吗?还有什么问题?

    3 回复  |  直到 14 年前
        1
  •  18
  •   Senseful    14 年前

    问题是我没有意识到 deleted 在这种情况下是保留字。我必须重新命名这个字段,它工作得很好。

        2
  •  4
  •   PeyloW    14 年前

    您需要为 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;
        }
    }
    
        3
  •  0
  •   JeremyP    14 年前

    在我看来,从错误消息中可以很清楚地看到,nsfetchedResultsController不希望您在创建后更改其获取请求。

    您需要做的是在 NSFetchedRequestController 已初始化。如果要在应用程序运行时更改fetch请求的谓词,可能需要创建一个新的nsfetchedRequestController并完全替换旧的谓词。