首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UITableViewDiffableDataSource能检测到更改的项目吗?

UITableViewDiffableDataSource能检测到更改的项目吗?
EN

Stack Overflow用户
提问于 2020-04-07 05:27:22
回答 3查看 6.1K关注 0票数 9

(这个问题在与下面的@AndreasOetjen讨论后被改写。(谢谢他的评论。)

我在使用UITableView和不同数据源时遇到了一个问题。在我的应用程序中,当用户修改一个项时,它可能会更改显示在同一个表视图中的另一个项。问题是,在我创建并应用了包含两个项的新值的新快照之后,间接更改的项的UI没有被更新。

起初,我认为不同的数据源能够在不同的快照中检测到项的值变化。例如,它可能是这样工作的:如果发现两个快照都包含相同的项(即两个快照中的项具有相同的散列值),则比较它们的值,并在值更改时在表视图中更新该项的行。但是,我后来意识到它可能不是这样工作的,因为不同的数据源没有定义任何API来获取和比较项值(我最初的想法是它使用了description计算属性和==操作,但现在我认为它不是真的)。

因此,我目前的理解是,不同的数据源使用项的散列来检测项顺序更改(即插入新项、旧项仍然存在等),而不是项值更改(即旧项仍然存在但值发生了变化)。如果这种理解是正确的,那么就引出了这个问题:如何使用不同的数据源来实现以下场景?

  • 一个项有几个属性。UI中显示了一个属性(让我们称之为属性A),但它不用于生成散列。
  • --该项存在于旧的和新的快照中,但其属性A发生了变化。因此,它的UI需要更新。

在旧的UITableView API中,这可以通过调用reloadRows()reloadData()来实现。但是如何使用不同的数据源来实现呢?

更新

在花时间做实验和解决问题后,我相信上述问题的理解是不正确的。请看下面我的回答。我相信这解释了数据源是如何工作的。我希望这对那些有同样困惑的人有所帮助。我很高兴被证明是错的。真的。所以,如果你有不同的想法,请留下你的答案。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-04-08 01:27:27

经过几乎一天的毫无头绪的实验,我相信我发现了不同的数据源是如何工作的,并在此基础上解决了我的问题(原来我的想法几乎是正确的)。

Diffable数据源使用项哈希标识项。对于旧的和新的快照中存在的同一项,不同的数据源通过使用旧的和新的值执行"==“操作来检查该项是否发生了更改。

一旦弄明白了,它看起来就像一个非常明显和简单的方法。但是它是如此的基本,以至于我无法理解为什么没有在任何地方明确地提到它。

所以,要回答我最初的问题,是的,不同的数据源可以检测到项值的变化。也就是说,当项值是引用类型和/或行中显示的文本是该对象引用的对象的属性(例如,核心数据中的关系)等时,就变得很棘手。

又一个音符。无论是使用整个项结构还是仅使用其一部分来生成项散列,只要它标识了项,都不重要。我宁愿只使用项目中真正确定它的重要部分。

票数 8
EN

Stack Overflow用户

发布于 2020-04-07 07:21:47

我对最后一句感到有点困惑:您写我的条目是一个枚举,具有关联的引用类型值,但是在上面的示例中,您使用了struct Book,它是一个值类型。无论如何,在任何情况下都必须牢记以下几点:

散列是关于“对象”身份的。这只是一种改善身份比较、折叠等的捷径。

如果提供自定义哈希实现,则两个对象ab的行为必须符合a == b所暗示的hash(a) == hash(b) (相反的方式几乎总是正确的,但可能存在冲突-特别是)。弱哈希算法--当情况并非如此时)。

因此,如果您只散列了titleauthor,那么您就必须实现比较操作符,因为它也只能比较titleauthor。然后,如果notes发生变化,数据源和任何实体都不会检测到身份更改。

UITableViewDiffableDataSource是一种便利视图和数据源之间插入/删除语句同步的方法。如果你拿到这个

*由于非正常异常“NSInternalInconsistencyException”终止应用程序,原因:“无效更新:无效节数。更新(3)后表视图中包含的节数必须等于更新(3)之前表视图中包含的节数,加上或减去插入或删除的节数(插入或删除的节数为0,2已删除)。”

那么,一个不同的数据源就是您的朋友。

我希望这能帮点忙。

票数 1
EN

Stack Overflow用户

发布于 2022-11-09 06:02:52

我也有同样的问题。经过一些研究,我认为Hashable不是处理更新特性的方法。您可以从这里的文档中看到它:https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/updating_collection_views_using_diffable_data_sources

它有两种方式来加载不同的数据源:Load the Diffable Data Source with IdentifiersPopulate Snapshots with Lightweight Data Structures

而第一个是苹果公司推荐的。其中,我们使用snapshot.reconfigureItems更新现有项。

代码语言:javascript
复制
    struct Recipe: Identifiable, Codable {
        var id: Int
        var title: String
        
        // and many other properties
        xxxxx
    }

    // Get the diffable data source's current snapshot.
    var snapshot = recipeListDataSource.snapshot()
    // Update the recipe's data displayed in the collection view.
    snapshot.reconfigureItems([recipeId])
    recipeListDataSource.apply(snapshot, animatingDifferences: true). 

重点不是在快照中使用Recipe,而是使用Recipe.ID,类型是NSDiffableDataSourceSnapshot<RecipeListSection, Recipe.ID>

第二种方法,我们都在使用,把可使用的模型放在快照中,以下是苹果公司对它的看法:

这种方法的缺点是,不同的数据源不能再跟踪身份。当现有项发生更改时,不同的数据源将更改视为对旧项的删除和新项的插入。因此,集合视图将失去与该项相关联的重要状态。例如,当项目的任何属性发生更改时,选中的项就会被取消选择,因为从不同数据源的角度来看,应用程序删除了该项,并添加了一个新的项来代替它。此外,如果应用快照时animatingDifferences为真,则每次更改都需要对旧单元格进行动画处理,并在新单元格中进行动画处理,这可能会损害性能,并导致UI状态(包括动画)在单元格内丢失。此外,此策略禁止在使用数据结构填充快照时使用reconfigureItems(:)或reloadItems(:)方法,因为这些方法需要使用正确的标识符。更新现有项数据的唯一机制是应用包含新数据结构的新快照,这将导致不同数据源对每个更改的项执行删除和插入操作。直接将数据结构存储到不同的数据源和快照中对于许多实际的用例来说并不是一个健壮的解决方案,因为数据源失去了跟踪身份的能力。仅将此方法用于简单的用例,在这些用例中,项目不会更改,比如本示例中的侧栏项,或者当项的标识不重要时。对于所有其他用例,或者当对使用哪一种方法有疑问时,用适当的标识符填充不同的数据源和快照。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61073340

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档