是否可以从 NSFetchedResultsController 获取最新的快照

Is it possible to source an up-to-date snapshot from an NSFetchedResultsController

从 iOS 13 开始,保持 UITableViewNSFetchedResultsController 同步的最简单方法似乎是使用快照。

只要 managedObjectContext 报告添加、删除或更新,NSFetchedResultsController 就会向其委托提供快照引用。使用快照时(NSDiffableDataSourceSnapshot),只有一个 FRC 委托方法需要实现:controller(_:didChangeContentWith:)。为了使该委托方法起作用,必须键入 UITableViewDiffableDataSource 和快照 <String, NSManagedObjectID>.

有效

但是如果需要更新整个 table 怎么办?使用 tableView.reloadData()frc.performFetch() 似乎是反模式。

编辑

我手动构建了一个快照,并在需要时调用应用。但是由于我的快照是基于 NSFetchedResultsSectionInfo 对象的,所以我似乎在复制 FRC 已经可用的内容:Hashable section titles 和 Hashable NSManagedObjectIDs

对于我之前(已删除)的回答,我深表歉意。快照与核心数据上下文无关。

NSFetchedResultsControllerCore Data 结合使用的目的是在保存 NSManagedObjectContext 时更新 UI。

为了能够控制 diffable 数据源的动画(以解决荒谬的行为),您必须继承 UITableViewDiffableDataSource 并添加 属性 animatingDifferences。进一步在子类中采用NSFetchedResultsControllerDelegate(在视图控制器中采用而不是)。

class DiffableCoreDataSource: UITableViewDiffableDataSource<String,NSManagedObjectID> {
    var animatingDifferences = false
}

extension DiffableCoreDataSource : NSFetchedResultsControllerDelegate
{
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
        apply(snapshot as NSDiffableDataSourceSnapshot<String, NSManagedObjectID>, animatingDifferences: animatingDifferences)
        animatingDifferences = true // set it to the default
    }
}

在视图控制器中,将 FRC 的 delegate 设置为子类,假设有一个 dataSource 属性 表示 DiffableCoreDataSource

frc.delegate = dataSource

如果更新记录,请在保存上下文之前将 dataSource.animatingDifferences 设置为 false

重新加载整个 table 视图调用 frc.performFetch()。切勿在 table 视图上调用 reloadData()

TL;DR:尽管 NSFetchedResultsController 能够在 managedObjectContext 报告添加、删除和更新时为其委托提供最新的快照引用,但不可能(至少目前)以编程方式直接从 FRC 访问快照。

正如 vadian 上面所建议的,使用 FRC 实例方法 performFetch() 将最新的快照应用到 DiffableData-backed UITableview 中的所有单元格。这是一种未记录的快照管理方法。但它允许单独使用 FRC 提供的快照,而不必编写独立的快照。更少的代码,以及用于快照更新的 'single-source-of-truth'。

根据其他人的反馈,缺点是 apply(_: animatingDifferences:) 方法中的 animatingDifferences 参数如果设置为 true 会触发错误。两个可重现的错误是 table 在第一次应用快照时根本无法加载。如果尝试使用 trailingSwipeActionsConfigurationForRowAt 方法或其他方法删除记录,另一个错误是应用程序崩溃。因此,使用这种后门方法的唯一方法是在所有情况下都将该 bool 设置为 false。这意味着,嗯,没有动画。