gpt4 book ai didi

ios - NSDiffableDataSourceSnapshot `reloadItems` 有什么用?

转载 作者:行者123 更新时间:2023-12-01 21:17:35 25 4
gpt4 key购买 nike

我很难找到使用 NSDiffableDataSourceSnapshot reloadItems(_:) :

  • 如果我要求重新加载的项目与数据源中已经存在的项目不相等,我会崩溃:

    Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to reload item identifier that does not exist in the snapshot: ProjectName.ClassName


  • 但是,如果该项目等同于数据源中已经存在的项目,那么“重新加载”它的意义何在?

  • 您可能会认为第二点的答案是:嗯,项目标识符对象的某些其他方面可能不是其等价性的一部分,但确实反射(reflect)到单元格界面中。但我发现那不是真的。调用 reloadItems 后, TableView 不反射(reflect)更改。
    因此,当我想更改一个项目时,我最终对快照所做的是 insert在要更换的项目之后,然后是 delete的原始项目。没有快照 replace方法,这正是我所希望的 reloadItems结果会是。
    (我对这些术语进行了 Stack Overflow 搜索,但发现很少——主要是几个对 reloadItems 的特定用途感到困惑的问题,例如 How to update a table cell using diffable UITableView 。所以我以更笼统的形式问,什么实用有没有人发现这种方法?)

    好吧,没有什么比拥有一个可重复的最小示例更可取的了,所以这里有一个。
    使用模板 ViewController 制作一个普通的 iOS 项目,并将此代码添加到 ViewController。
    我一 block 一 block 来。首先,我们有一个结构将用作我们的项目标识符。 UUID 是唯一的部分,因此等价性和哈希性仅取决于它:
    struct UniBool : Hashable {
    let uuid : UUID
    var bool : Bool
    // equatability and hashability agree, only the UUID matters
    func hash(into hasher: inout Hasher) {
    hasher.combine(uuid)
    }
    static func ==(lhs:Self, rhs:Self) -> Bool {
    lhs.uuid == rhs.uuid
    }
    }
    接下来,(假) TableView 和可区分的数据源:
    let tableView = UITableView(frame: .zero, style: .plain)
    var datasource : UITableViewDiffableDataSource<String,UniBool>!
    override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
    self.datasource = UITableViewDiffableDataSource<String,UniBool>(tableView: self.tableView) { tv, ip, isOn in
    let cell = tv.dequeueReusableCell(withIdentifier: "cell", for: ip)
    return cell
    }
    var snap = NSDiffableDataSourceSnapshot<String,UniBool>()
    snap.appendSections(["Dummy"])
    snap.appendItems([UniBool(uuid: UUID(), bool: true)])
    self.datasource.apply(snap, animatingDifferences: false)
    }
    所以我们的 diffable 数据源中只有一个 UniBool 及其 booltrue .所以现在设置一个按钮来调用这个尝试切换 bool 的操作方法。使用 reloadItems :
    @IBAction func testReload() {
    if let unibool = self.datasource.itemIdentifier(for: IndexPath(row: 0, section: 0)) {
    var snap = self.datasource.snapshot()
    var unibool = unibool
    unibool.bool = !unibool.bool
    snap.reloadItems([unibool]) // this is the key line I'm trying to test!
    print("this object's isOn is", unibool.bool)
    print("but looking right at the snapshot, isOn is", snap.itemIdentifiers[0].bool)
    delay(0.3) {
    self.datasource.apply(snap, animatingDifferences: false)
    }
    }
    }
    事情就是这样。我对 reloadItems 说与 UUID 匹配的项目,但其 bool已切换:“此对象的 isON 为假”。但是当我问快照时,好吧,你有什么?它告诉我它唯一的项目标识符是 bool仍然是真的。
    这就是我要问的。如果快照不会获取 bool 的新值, 什么是 reloadItems首先是为了?
    显然,我可以只替换一个不同的 UniBool,即一个具有不同 UUID 的 UniBool。但是我不能调用 reloadItems ;我们崩溃是因为 UniBool 还没有在数据中。我可以通过调用 insert 来解决这个问题。后跟 remove ,这正是我解决它的方法。
    但我的问题是:那么 reloadItems 是什么?因为,如果不是为了这件事呢?

    最佳答案

    (我已经就问题中展示的行为提交了一个错误,因为我认为这不是好的行为。但是,就目前情况而言,我认为我可以猜测这个想法的意图。)

    当您将快照告诉 reload某个项目,它不会读入您提供的项目的数据!它只是查看项目,作为识别数据源中已经存在的项目的一种方式,您要求重新加载。
    (因此,如果您提供的项目与数据源中已有的项目相同但不是 100% 相同,那么您提供的项目与数据源中已有的项目之间的“差异”将 根本不重要 ;永远不会告诉数据源有什么不同。)
    当你然后apply该快照到数据源,数据源告诉 TableView 重新加载相应的单元格。这会导致再次调用数据源的单元格提供程序函数。
    好的,所以调用了数据源的单元格提供程序函数,使用了通常的三个参数——表格 View 、索引路径和来自数据源的数据。但是我们刚才说过,来自数据源的数据没有改变。那么重新加载有什么意义呢?
    显然,答案是单元格提供程序函数有望在别处寻找以获取(至少部分)要在新出列的单元格中显示的新数据。您应该有某种单元提供者查看的“后备存储”。例如,您可能正在维护一个字典,其中键是单元标识符类型,值是可能重新加载的额外信息。
    这必须是合法的,因为根据定义,单元标识符类型是可散列的,因此可以用作字典键,而且单元标识符在数据中必须是唯一的,否则数据源会拒绝数据(通过崩溃)。并且查找将是即时的,因为这是一本字典。

    这是一个完整的工作示例,您可以直接复制并粘贴到项目中。该表格描绘了三个名称以及一个星形,用户可以点击星形来填充或空出星形,表示喜欢或不喜欢。名称存储在 diffable 数据源中,但收藏状态存储在外部后备存储中。

    extension UIResponder {
    func next<T:UIResponder>(ofType: T.Type) -> T? {
    let r = self.next
    if let r = r as? T ?? r?.next(ofType: T.self) {
    return r
    } else {
    return nil
    }
    }
    }
    class TableViewController: UITableViewController {
    var backingStore = [String:Bool]()
    var datasource : UITableViewDiffableDataSource<String,String>!
    override func viewDidLoad() {
    super.viewDidLoad()
    let cellID = "cell"
    self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
    self.datasource = UITableViewDiffableDataSource<String,String>(tableView:self.tableView) {
    tableView, indexPath, name in
    let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
    var config = cell.defaultContentConfiguration()
    config.text = name
    cell.contentConfiguration = config
    var accImageView = cell.accessoryView as? UIImageView
    if accImageView == nil {
    let iv = UIImageView()
    iv.isUserInteractionEnabled = true
    let tap = UITapGestureRecognizer(target: self, action: #selector(self.starTapped))
    iv.addGestureRecognizer(tap)
    cell.accessoryView = iv
    accImageView = iv
    }
    let starred = self.backingStore[name, default:false]
    accImageView?.image = UIImage(systemName: starred ? "star.fill" : "star")
    accImageView?.sizeToFit()
    return cell
    }
    var snap = NSDiffableDataSourceSnapshot<String,String>()
    snap.appendSections(["Dummy"])
    let names = ["Manny", "Moe", "Jack"]
    snap.appendItems(names)
    self.datasource.apply(snap, animatingDifferences: false)
    names.forEach {
    self.backingStore[$0] = false
    }
    }
    @objc func starTapped(_ gr:UIGestureRecognizer) {
    guard let cell = gr.view?.next(ofType: UITableViewCell.self) else {return}
    guard let ip = self.tableView.indexPath(for: cell) else {return}
    guard let name = self.datasource.itemIdentifier(for: ip) else {return}
    guard let isFavorite = self.backingStore[name] else {return}
    self.backingStore[name] = !isFavorite
    var snap = self.datasource.snapshot()
    snap.reloadItems([name])
    self.datasource.apply(snap, animatingDifferences: false)
    }
    }

    关于ios - NSDiffableDataSourceSnapshot `reloadItems` 有什么用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64081701/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com