iOS UICollectionViewDiffableDataSource 使用

5 阅读1分钟

🧩 iOS UICollectionViewDiffableDataSource 使用指南(实战版)

适用于:UIKit 项目 / UICollectionView 目标:用最少代码实现稳定、可维护、带动画的数据更新


✨ 一、为什么要用 Diffable?

传统方式:

performBatchUpdates {
    insertItems / deleteItems
}

问题:

  • ❌ 容易崩溃(indexPath 不一致)
  • ❌ 代码复杂
  • ❌ 和自定义 layout 动画冲突

✅ Diffable 核心思想

👉 用“数据快照(Snapshot)”驱动 UI


🧠 二、步骤总览

1️⃣ 定义 Section 2️⃣ 定义 Item(必须 Hashable) 3️⃣ 创建 DataSource 4️⃣ 构建 Snapshot 5️⃣ 应用 Snapshot


🧩 三、定义数据模型

enum Section: Hashable {
    case main
}
​
struct ImageItem: Hashable {
    let id: UUID
    let name: String
}

🏗 四、创建 DataSource

var dataSource: UICollectionViewDiffableDataSource<Section, ImageItem>!
​
dataSource = UICollectionViewDiffableDataSource(
    collectionView: collectionView
) { collectionView, indexPath, item in
​
    let cell = collectionView.dequeueReusableCell(
        withReuseIdentifier: "ImageCell",
        for: indexPath
    ) as! ImageCell
​
    cell.imageView.image = UIImage(named: item.name)
    return cell
}

🔥 五、创建并应用 Snapshot

func applySnapshot(animated: Bool = true) {
    var snapshot = NSDiffableDataSourceSnapshot<Section, ImageItem>()
​
    snapshot.appendSections([.main])
    snapshot.appendItems(items, toSection: .main)
​
    dataSource.apply(snapshot, animatingDifferences: animated)
}

➕ 六、添加数据

func addItem() {
    let item = ImageItem(id: UUID(), name: "image_1")
    items.append(item)
    applySnapshot()
}

➖ 七、删除数据

func deleteItem(at indexPath: IndexPath) {
    let item = items[indexPath.item]
    items.removeAll { $0.id == item.id }
    applySnapshot()
}

🎬 八、动画说明

applySnapshot()

自动获得:

  • 插入动画
  • 删除动画
  • 移动动画

⚠️ 九、重要注意事项

❌ 不要再使用:

performBatchUpdates

❌ 不要手动操作 indexPath


❌ 不要同时做:

更新数据 + 切换 layout

✅ 正确顺序

applySnapshot()
​
DispatchQueue.main.async {
    collectionView.setCollectionViewLayout(layout, animated: true)
}

🚀 十、总结

👉 DiffableDataSource = 更安全的数据驱动 UI 👉 不再关心 indexPath 👉 自动动画


🎯 推荐使用场景

  • 拼图 App
  • 图片列表
  • 聊天列表
  • 商品列表

如果你觉得有用,欢迎点赞 👍