在WWDC2019,苹果推出了一种在UITableView和UICollectionView使用的全新数据源的设置方式:UITableViewDiffableDataSource
和UICol数组的定义lectionViewDiffableDataSource
,支持iOS13及以上版本使用。
先来看看我们用了10年的dataSource是如何设置的:
- 设置section数量;
- 设置iios下载tapp小胖子em数量;
- 设置相应的cell;
这样设置dat数组和链表的区别aSource经常会出现像下面所示的crash:
遇到这种问题的时候appreciate,通常是因为在操作indexPath
和数据源的过程中导致的数组越苹果官网界,有时候debug起来并不简单。经常你会通过调数组词多音字组词用reloadData()
解决问题,但是apple苹果官网reloadData()
不带动画,这就降低了用户体验。而且有时候你并不希望刷新整个视图。
接下来看看DiffableDataSource的用法
因为DiffableDataSource在TableView和CollectionView的用法类似,所以下面用TableView来演示数组。
-
首先先了appstore解一个关键的东西:
NSDiffableDataSourceSnapshot
:我们可以理解它是一个快照
,我们需要给这个快照设置相应的section和item,并将此快照apple苹果官网apply到dataSource上,后续可以修改快照的内容,改变显示的结果。 -
再来看看苹果怎么定义
UITableViewDiffableDataSource
的:这里苹果手机看得出
SectionIdentifierType
和ItemIdentifierType
都是需要遵从Hashable
的,目的是确保唯一性。 -
我们先定义一个遵从
Hashable
的SecappletionIdentifierType
和ItemIdentifierType
:// 枚举默认就是Hashable类型 enum Section: CaseIterable { case main } // 自定义类型需要遵从Hashable协议 struct MyModel: Hashable { var title: String init(title: String) { self.title = title self.identifier = UUID() } private let identifier: UUID func hash(into hasher: inout Hasher) { hasher.combine(self.identifier) } }
-
定义使用
Section
、MyMapple storeodel
的appearancedataSource:private var dataSource: UITableViewDiffableDataSource<Section, MyModel>! = nil
-
设置tableView的UI、dataSource,生成snapShot并将它用到dataSource上:
// 这是即将用来展示的models private lazy var mainModels = [MyModel(title: "Item1"), MyModel(title: "Item2"), MyModel(title: "Item3")] // tableView private lazy var tableView: UITableView = { let tableView = UITableView(frame: .zero, style: .insetGrouped) tableView.translatesAutoresizingMaskIntoConstraints = false tableView.register(UITableViewCell.self, forCellReuseIdentifier: "identifier") tableView.delegate = self return tableView }() override func viewDidLoad() { super.viewDidLoad() setupTableView() // 设置tableView UI setupDataSource() // 设置tableView的dataSource applySnapshot() // 给dataSource设置snapshot } func setupTableView() { view.addSubview(tableView) NSLayoutConstraint.activate([ tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } func setupDataSource() { dataSource = UITableViewDiffableDataSource<Section, MyModel>.init(tableView: self.tableView, cellProvider: {(tableView, indexPath, model) -> UITableViewCell? in let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) var content = cell.defaultContentConfiguration() content.text = model.title cell.contentConfiguration = content return cell }) dataSource.defaultRowAnimation = .fade } func applySnapshot() { // 往snapshot里插入sections和items var snapshot = NSDiffableDataSourceSnapshot<Section, MyModel>() snapshot.appendSections([.main]) snapshot.appendItems(mainModels, toSection: .main) dataSource.apply(snapshot, animatingDifferences: true) }
运行效果如下:
-
当我们需要修改数据,比如点击了就删掉该行,可以用2种方式实现,个人觉得第2种比较方便一点,不用手动操作snapshot中的item:
- 方法1(不推荐,代码容易出错):
- 用
snapshot()
取到当ios是什么意思前的snapshot; - 删掉snapshot中对应的item;
- 删掉mainModels中的mo数组去重del;
- 将改变后的snapshot运用到dataSource上;苹果12
- 用
extension ViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 取到当前的snapshot var snapshot = dataSource.snapshot() // 删掉snapshot中对应的item let item = mainModels[indexPath.row] snapshot.deleteItems([item]) // 删掉mainModels中的model mainItems.remove(at: indexPath.row) // 将改变后的snapshot运用到dataSource上 dataSource.apply(snapshot, animatingDifferences: true) } }
- 方法2:
- 删掉mainModels中的model;
- 生成一个新的空snapshot;
- 重新将section、item等数据加到snapshot中;
- 将新的snapshot运用到dataSource上去;
extension ViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { mainItems.remove(at: indexPath.row) applySnapshot() } }
运行效果:
- 方法1(不推荐,代码容易出错):
参考资料:
- WWDC2019 – Advances in UI Data Sources
- Mode苹果12rn table views with diffablApplee data sources
- Apple documentation – UITableViewDiffableDataSource
- Apple documentation – NSDiffableDataSourceSnapsho数组公式t
- UITableView和UICollectionView的新渲染方式DiffableDataSource