【问题标题】:Infinite loop in NSFetchedResultsControllers controllerDidChangeContent methodNSFetchedResultsControllers controllerDidChangeContent 方法中的无限循环
【发布时间】:2014-08-03 09:47:15
【问题描述】:

我有UITableViewController 表并使用NSFetchedResultsController 从Core Data 获取行。我的tableView 负责分层数据。每个行位置表示层(在零行最高层,n - 最低行)。假设我们有名称为Layers *layers 的对象。当我创建新层时,它需要转到表中的第一行(indexPath.row == 0)并且需要获取layers.layer.position = 0。当我创建新层或进行其他一些更改(移动、删除)时,我需要刷新核心数据对象layers(每个层都需要获取新的位置值)。但是,如果我通过在controllerDidChangeContent 方法旁边调用[self updateLayersPosition] 方法来刷新图层位置,它会进入无限循环,因为每次更改每个旧图层值时,它都会一次又一次地返回到相同的controllerDidChangeContent 方法。所以问题是如何“绑定”表行或获取的控制器indexPath.rowlayers.layer.position?也许我可以停止fetchedresultscontroller 获取,进行更新然后再次开始获取?或者也许有其他方法可以做到这一点?

代码如下:

-(void)updateLayers{
    for (int i = 0; i < [self.tableView numberOfRowsInSection:0]; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i 
                                                    inSection:0];
            ((Layer *)[self.fetchedResultsController objectAtIndexPath:indexPath]).layer.position = i;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    [self updateLayers];
    [self.tableView endUpdates];
}

【问题讨论】:

  • 您不能对controllerDidChangeContent: 中的上下文进行任何更改,这显然会导致无限循环。
  • 那么在哪里可以安全地调用该方法?
  • 取决于您对应用程序的编程方式。不过不在这里。
  • 但是如果我想让 UITableViewController 负责“分层”,那么其他类中就不需要我的代码了。如果我向图层对象添加新图层会很好,这个 UITableViewController 类为我做分层。那么我需要使用 NSFetchedResultsController 或 UITableViewController 的什么方法来更改具有 indexPath.row 值依赖关系的 layers.layer.position 值?

标签: ios uitableview core-data nsfetchedresultscontroller infinite-loop


【解决方案1】:

NSFetchedResultsControllerDelegate 中的所有 willChange / didChange 方法在您修改 Core Data 对象后被调用。所以如果你修改controllerDidChangeContent:里面的任何NSManagedObject,都会再次触发controllerDidChangeContent:,导致死循环。

您可以将这些委托回调视为一个控制器,说“您已经更改了核心数据模型中的某些内容,现在让我们更新 UI(UITableView)。您应该遵循的一般模式是:

  • NSManagedObjects 中进行一项或多项更改(添加、修改、删除)
  • 保存NSManagedObjectContext
  • NSFetchedResultsControllerDelegate 的方法中:更新UITableView 以反映更改(添加、重新加载、删除表视图行)

所以你可能想做这样的事情:

//in the method in which you add a new Layer object
- (void)addLayer {
  Layer *layer = [NSEntityDescription insertNewObjectForEntityForName:@"Layer" inManagedObjectContext:context];
  //recalculate the position of all the other layers
  //save NSManagedObjectContext
}

关键是添加新层后立即更新每个层的position,然后保存上下文。然后NSFetchedResultsController 将按照您的需要将层的位置“绑定”到表中的行(我假设您在获取请求中使用的排序描述符中使用position 属性)。如果您按照documentation 中的建议实现这些NSFetchedResultsControllerDelegate 方法,它应该可以完成这项工作:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
    atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
    newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
                  atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}

【讨论】:

  • 我按照你说的做了我在 addLayer 方法中实现了我的所有代码,现在分层工作!谢谢。
猜你喜欢
  • 1970-01-01
  • 2015-12-28
  • 1970-01-01
  • 1970-01-01
  • 2014-03-21
  • 1970-01-01
  • 2019-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多