在 iOS 13 中 Apple 为 UITableView 和 UICollectionView 引入了 DiffableDataSource,让开发者可以更简单高效的实现 UITableView、UICollectionView 的局部数据刷新。新的刷新的方法为 apply,通过使用 apply 方法无需计算变更的 indexPaths,也无需调用 reload,即可安全地在主线程或后台线程更新 UI, 仅需简单的将需要变更后的数据通过 NSDiffableDataSourceSnapshot 计算出来。下面以 UITableView 为例进行讲解。
var dataSource: UITableViewDiffableDataSource<Section, City>!
override func viewDidLoad() {
super.viewDidLoad()
dataSource = UITableViewDiffableDataSource
<Section, City>(tableView: tableView) {
(tableView: UITableView, indexPath: IndexPath,
city: City) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = city.name
return cell
}
dataSource.defaultRowAnimation = .fade
}
enum Section: CaseIterable {
case main
}
var snapshot = NSDiffableDataSourceSnapshot<Section, City>()
snapshot.appendSections([.main])
snapshot.appendItems(filteredCities, toSection: .main)
dataSource.apply(snapshot, animatingDifferences: true)
struct City: Hashable {
let name: String
let identifier = UUID()
func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
}
static func ==(lhs: City, rhs: City) -> Bool {
return lhs.identifier == rhs.identifier
}
func contains(query: String?) -> Bool {
guard let query = query else { return true }
guard !query.isEmpty else { return true }
return name.contains(query)
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let city = dataSource.itemIdentifier(for: indexPath) {
print("选择了\(city.name)")
}
}
}
前面介绍的是 UITableView 的关键使用步骤,UIColletionView 使用类似,完整案例详见下面的链接: