如何使用 diffable UITableView 更新表格单元格

use*_*508 8 uitableview

我在 UITableView 中使用了新的 NSDiffableDataSourceSnapshot 和 UITableViewDiffableDataSource。我在构建表格时没有问题,但是当单元格中显示的数据发生变化时,我在更新单元格时遇到问题。我还没有找到任何解释如何执行此操作的 Apple 文档。我尝试了以下方法:

self.currentSnapshot.reloadItems([Item(identifier: identifier)])
self.dataSource.apply(self.currentSnapshot)
Run Code Online (Sandbox Code Playgroud)

我在 reloadItems 中收到以下错误:

断言失败 -[__UIDiffableDataSourceSnapshot _reloadViewUpdatesForDiffUpdate:dataSource:ignoreInvalidItems:]

我已经检查过传递给 Item 初始值设定项的标识符是否已经存在于快照中。

这是我的项目类:

class Item: Hashable, Equatable {

    let identifier: String
    var matchWrapper: MatchWrapper

    init(matchWrapper: MatchWrapper) {
        self.identifier = matchWrapper.identifier
        self.matchWrapper = matchWrapper
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(self.identifier)
    }

    static func == (lhs: ScoresViewController.Item, rhs: ScoresViewController.Item) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}
Run Code Online (Sandbox Code Playgroud)

有什么建议?

小智 7

我遇到过类似的问题,经过大量调试和尝试不同的东西后,我得出的结论是,我认为您不应该使用reloadItems. reloadItems从我的测试中实际上似乎没有做任何事情。单元提供程序始终提供旧数据,如果您有一个基于标识符的哈希函数和一个可检查除标识符以外的事物是否相等的可等式函数,则会出现错误。

您可以尝试两件事

  1. 如果你真的想在 cellProvider 中使用 reload 项而不是使用闭包提供的数据,请使用你自己的数据源作为真实来源来布置单元格。(尽管在我看来,这种方式违背了 diffableDataSource 的目的)。您最终会错过 DiffableDataSource 的一些重要功能

  2. 而不是像这样编写代码:

var snapshot = tableView.snapshot()
let item = items[indexPath.row]
snapshot.reloadItems([item]) 
Run Code Online (Sandbox Code Playgroud)

你可以这样做

let snapshot: NSDiffableDataSourceSnapshot<Section,Item> = .init() 
// assuming wherever you're storing your data is already updated 
snapshot.appendItems([items])
dataSource.apply(snapshot)  
Run Code Online (Sandbox Code Playgroud)

这应该只刷新快照中发生更改的项目。根据我的理解,tableView 的当前快照与新创建的快照进行比较,只有不同的项目才应该更新。我在这里可能是错的,但这对我有用。

我见过的其他建议:

  • 编写您的哈希函数,结合视图中可以更改的所有值。
func hash(into hasher: inout Hasher) {
  hasher.combine(id)
  hasher.combine(name)
  hasher.combine(title)
}
Run Code Online (Sandbox Code Playgroud)

但是,如果你走这条路线,这意味着 reloadItems 将抛出一个错误报告,这在数据源中不存在,因此你必须添加它并手动删除旧数据