使用diff框架更新Swift中UICollectionView数据的更好方法

熟悉的朋友

通过iOS中的UITableViewNSCollectionView ,macOS中的tvOS或NSTableViewNSCollectionView NSTableView ,很难想象没有使用表视图或集合视图的应用程序。 大多数时候,我们从后端,缓存和过滤器中获取数据,以列表或网格形式显示该数据。 之后,当数据更改时,我们将更新您的界面以反映某些项目已被插入或删除。

那就是您最喜欢的函数出现的地方reloadData 。 这样,整个列表将以全新的内容刷新。 当您需要快速刷新内容的方案时,这是很好的选择。 但这会使UITableView再次使单元格大小无效,这会降低性能。 此外,如果这些更改应引起注意,并且您想让用户更好地了解发生了什么,那么最好手动插入和删除行。

如果您使用的是Android,则可能知道不用调用notifyDataSetChanged ,而可以使用提供的DiffUtil为我们计算更改,从而使RecyclerView更新变得容易。 不幸的是,您在iOS中没有那么奢侈,但是我们可以学习如何做到这一点。

本指南以UICollectionView为例,但UITableView行为相同。 对于在Google上搜索NSCollectionView任何人来说,这都有点困难:

拖放

让我们看UICollectionView情况。 想象一下一个应用程序,在该应用程序中,用户可以通过将项目从一个集合移到另一个集合来自定义其体验。

您可以看一下示例DragAndDrop,它在iOS 11中使用了新的拖放API。

UICollectionView上调用更新方法之前,必须确保数据已更改。 然后我们调用deleteItemsinsertItems以反映数据更改。 UICollectionView为您执行漂亮的动画

索引与偏移

在我们进行进一步讨论之前,我只想提及一下,实际上是指从一开始的offset 。 如果您看一下枚举函数,它建议使用名称作为偏移量而不是索引

编辑距离

手工进行这些计算非常繁琐且容易出错。 我们可以使用一些算法来构建自己的抽象。 天真的是Wagner-Fischer算法,该算法使用动态编程来告诉两个字符串之间的编辑距离。

编辑距离是指从一个字符串更改为另一个字符串所需的步数。 字符串只是字符的集合,因此我们可以推广这个概念以使其适用于任何项目集合。 而不是比较字符,我们要求项目符合Hashable

从“套件”到“ kat”

我们如何将“套件”一词的形式转换为“ kat”? 我们需要执行哪种操作? 您可能会说“只是将字母i更改为a”,但是这个简单的示例可以帮助您理解算法。 让我们开始吧。

删除项

如果从“ kit”转到空字符串“”,则需要删除3次

“套件”->“”” 3个删除项

“ ki”->“”” 2个删除

“ k”->“”” 1删除

插入

如果从空字符串“”转到“ kat”,则需要插入3次

“”->“ k”👉1插入

“”->“ ka”👉2个插入

“”->“ kat”👉3次插入

如果相等,则从左上角取值

您可以认为算法就像我们从源字符串到空字符串再到目标字符串一样。 我们尝试找到更新的最小步骤。 水平表示插入,垂直表示删除,对角线表示替换。

这样,我们可以构建矩阵,逐行逐列迭代。 首先,源集合中的字母“ k”与目标集合中的字母“ k”相同,我们仅从左上角取值,即0替换

如果不相等

我们继续处理目标集合中的下一封信。 这里的“ k”和“ a”不相同。 我们从左,上,左上取最小值。 然后加一

在这里,我们从水平方向的左侧获取值,因此我们增加了1次插入。

“ k”到“ kat”👉2次插入

继续,“ t”和“ k”不相同,因此我们从左向左取值。 从“ k”到“ kat”,我们需要2次插入,即插入字母“ a”和“ t”,在这里您会发现这很有意义。

右下角的值

继续下一行和下一行,直到我们到达右下角的值为止,该值为您提供了编辑距离。 在这里1替换意味着我们需要执行1替换才能从“套件”变为“ kat”,即用“ a”’更新“ i”。

您可以轻松地看到我们需要更新索引1。但是我们如何知道它是索引1🤔

深度差异

该算法显示了2个字符串之间的变化,但是由于string只是字符的集合。 我们可以概括该概念以使其适用于任何项目集合。

DeepDiff的实现在GitHub上。 这是它的用法。 给定一个old数组,它将计算转换所需的更改。 更改包括:更改类型( insertdeletereplacemove )和更改index

IGListKit也实现了该Heckel算法,但是在Objective C ++中进行了大量优化。 在下一篇文章中,我将介绍Heckel算法以及如何在纯Swift中实现它,以及如何为这些diff算法编写单元测试。 敬请关注!

同时,如果您喜欢冒险,可以参考以下一些非常有效的算法:

  • O(ND)差分算法及其变化
  • O(NP)序列比较算法