复杂列表的有效实现

2,088 阅读3分钟

最近一直在做项目优化,由于项目中有一个 xx墙 的列表界面,Cell的样式复杂,与用户的互动,cell变化也比较多,所以在实现上,代码很臃肿,比较杂乱,日常的维护不是特别方便,随着时间的推移,这个问题肯定越来越麻烦,所以一直在找神马方法来有效的处理这个问题。

之后就找到了IGListKit这个库,其实这个库在很早之前就有所接触,当时只是简单的了解了一下,看了它能实现的东西,自己原生也能写出来,就没有去深入的学习它。现在再想想,是以前自己太幼稚了。

其实,IGListKit这个库的目的性很强,它就是来解决一个布局复杂多样,交互比较多的列表的编写和维护难的问题,官方对其的描述是:A data-driven UICollectionView framework for building fast and flexible lists.,这也刚好,符合我的需求。

Diff

Diff 指的是在新旧的数据中,找出不同。IGListKit中,我觉得最后特色的地方,是它的 Diff 方案,IGListKit的 Diff 结合了Paul Heckel’s Diff(1978年)的一篇论文,进一步优化,使用额外一些内存空间,降低时间复杂度到O(n),并且能准确获取所有Insert/Delete/Move操作。因此,IGListKit在更新列表内容时,并不是对所有的cell进行reloadData(),而是使用Diff算法,计算出新旧数据的差异,然后使用performUpdates进行小范围的insert/delete/move操作对数据发生变化的视图进行更新。

如何使用

  1. 创建 collectionViewadapter, 在 viewDidLayoutSubviews 中设置 collectionView.frame = view.bounds,设置 adapterviewControllerselfadaptercollectionView 为刚刚创建的 collectionView ,最后设置 adapterdataSourceself;

2.实现 ListAdapterDataSource 的方法

3. 从代码中可以看出,数组中的元素必须要实现 ListDiffable 协议,其目的是为了 Diff 运算。由于数组中的 String 类型的元素本身没有实现此协议,故使用了 data.map { $0 as! ListDiffable }

4. 之后就是根据数组中的元素的类型不同,返回不同的 SectionController, 不同的 SectionController 处理不同的类型的数据。其中,自定义的 SectionController 需要实现 numberOfItems()sizeForItem(at index: Int) -> CGSizecellForItem(at index: Int) -> UICollectionViewCelldidUpdate(to object: Any) 4个方法,另外还可以重写 ListSectionController 的其他方法来实现不同的需求,比如inset、space的设置、selected、highlight方法、以及supplementaryViewSource、displayDelegate、workingRangeDelegate、scrollDelegate这几种很好用的delegate。

部分说明

下图,挺形象的描述了 IGListKit 的实现(网络图片,借用一下)

  1. 其中 adapter 的角色是一个中心调度器,它作为 UICollectionView的datasource ,每次都会从 sectionController 中获取 cell,同时作为 UICollectionViewUIScrollView的delegate,负责向 sectionController回调。同时,adapter 对外提供 datasource 回调,外界需要提供 data 数组、sectionController 的对象实例、以及 empty view
  2. SectionController 中的 collectionContext 实际就是就是 adapter,上两者是相互引用的关系。
  3. 上述的Demo也可以用 IGListKit 内建的 ListBindingSectionController 来实现,具体看实现开发来选择用哪种。
  4. IGListKit 内建的 SectionController 还有 IGListSingleSectionController,可以构建简单的单个 cellSection
  5. IGListKit 内建的 SectionController 中的 IGListGenericSectionController,是在 IGListSectionController的基础上,自动添加了一个属性来存储 ``didUpdateToObject:方法中的Object`
  6. IGListKit 内建的 SectionController 中的 ListStackedSectionController,是将多个 SectionController组合在一个 SectionController 中处理。

参考

  1. Diff应用:从LCS到UICollectionView
  2. Getting Started Reference