NSFetchedResultsController 添加新记录时如何防止 UITableView 向上滚动?

How to prevent from scrolling UITableView up when NSFetchedResultsController add new record?

一旦我向 CoreData 添加新评论,我的 UITableView 就会向上滚动。 NSFetchedResultsController 知道它,将此注释放在 table 的底部,然后将 table 滚动到顶部。正常吗?

我的例子:

就在我添加评论之前:

在我添加评论之后(不是预期的行为):

应该是这样的(我手刷后):

这可能与以下情​​况有关:

  1. 这是我的排序描述符 NSFetchedResultsController:

    NSSortDescriptor(key: "createdAt", ascending: false) //from the latest to the oldest
    
  2. 但我需要显示我对反向索引路径的评论(最新的在最底部)。换句话说,当我需要使用 indexPath 时,我会在任何地方使用:

    private func reversedIndexPathForIndexPath(indexPath: NSIndexPath) -> NSIndexPath {
        return NSIndexPath(forRow: fetchedResultsController.fetchedObjects!.count - indexPath.row - 1, inSection: 0)
    }
    

NSFetchedResultsControllerDelegate:

//MARK: - NSFetchedResultsControllerDelegate

func controllerWillChangeContent(controller: NSFetchedResultsController) {
    self.tableView.beginUpdates()
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {

    switch type {
    case .Insert:
        if let newIndexPath = newIndexPath {
            tableView.insertRowsAtIndexPaths([reversedIndexPathForIndexPath(newIndexPath)], withRowAnimation: .Fade)
        }
    case .Delete:
        if let indexPath = indexPath {
            tableView.deleteRowsAtIndexPaths([reversedIndexPathForIndexPath(indexPath)], withRowAnimation: .Fade)
        }
    case .Update:
        if let indexPath = indexPath {
            tableView.reloadRowsAtIndexPaths([reversedIndexPathForIndexPath(indexPath)], withRowAnimation: .Fade)
        }
    case .Move:
        if let indexPath = indexPath, let newIndexPath = newIndexPath {
            tableView.deleteRowsAtIndexPaths([reversedIndexPathForIndexPath(indexPath)], withRowAnimation: .Fade)
            tableView.insertRowsAtIndexPaths([reversedIndexPathForIndexPath(newIndexPath)], withRowAnimation: .Fade)
        }
    }
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    tableView.endUpdates()
}

是否与我的问题有关?

编辑后的答案:

我能够通过以下步骤重现此故障:

  1. UITableViewrowHeight 设置为 UITableViewAutomaticDimension 且非零 estimatedRowHeight.
  2. Table 滚动到最底部,最后一个单元格在底部边缘完全可见。
  3. 在最后一个单元格下方插入新单元格会导致单元格的视觉偏移向下几个点(在我的设置中,它从 5 到 40 不等)。

此行为的来源需要进一步调查。

目前唯一的解决方案是不使用 tableView:heightForRowAtIndexPath:.

中的 UITableViewAutomaticDimension 和 return 行高

顺便说一下,倒排索引路径的实现有一个重大缺陷。当 FRC 调用它的委托方法 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 时,所有删除索引路径属于更改前的数据集,所有插入索引路径 - 到 post-更改一个。当你在 controllerWillChangeContent:controllerDidChangeContent: 之间时,fetchedResultsController.fetchedObjects 将包含 post-change 数据集,我想(虽然需要检查)。

我找到了适合我的东西。 我遇到了同样的问题,我的estimatedRowHeight是33,我所有的单元格都大于33。

我刚刚将 estimatedRowHeight 更改为我的最大单元格高度(或大于您的最大单元格高度)

    self.table.estimatedRowHeight = 310
    self.table.rowHeight = UITableViewAutomaticDimension

非常有效,当核心数据执行 update/delete/insert

时,所有单元格现在都自动调整大小并且 uitableview 不会滚动到顶部或底部