You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UICollectionViewDiffableDataSource中忽略重复数据项

问题根源

当前去重逻辑失效的核心原因是Fruit模型的Hashable/Equatable实现完全依赖实例初始化时自动生成的UUID:每次创建新的Fruit实例时,哪怕title完全一致,新实例的uuid是全新生成的值,和已有实例的uuid永远不相等,因此fruits.contains(fruit)判断永远返回false,重复数据会被持续插入列表。

实现方案

针对你同时对接接口数据、本地操作数据,且页面会重复触发接口拉取的场景,统一按业务唯一标识判断对象同一性即可,不要使用临时生成的UUID做判等依据。

1. 修正模型的Hashable/Equatable实现

根据业务规则确定唯一判断维度:如果是接口返回的数据,优先使用后端下发的固定业务ID(比如fruitId)作为判等依据;如果是简化场景下名称唯一,就用title做判等。==方法和hash方法的判断逻辑必须保持一致:

enum Section {
    case main
}

struct Fruit: Hashable {
    // 接口场景替换为后端下发的业务ID:let fruitId: String
    var title: String
    
    static func == (lhs: Fruit, rhs: Fruit) -> Bool {
        // 业务上认为两个对象是同一项的判断规则,多字段判断就并列加&&条件
        return lhs.title == rhs.title
    }

    func hash(into hasher: inout Hasher) {
        // 只组合参与==判断的字段
        hasher.combine(title)
    }
}

注意:如果本地新建的对象需要生成唯一ID,生成后必须做持久化存储,不要每次初始化模型时临时生成新的UUID,否则App重启、接口重新拉取时会生成全新ID,直接导致去重逻辑失效。

2. 封装通用的去重插入逻辑

写一个统一的数组插入方法,不管是本地新增还是接口返回的数据,都走这个方法自动过滤重复项:

// 存储水果的数组
private var fruits: [Fruit] = []

/// 统一的新增水果方法,自动过滤重复项
func addNewFruits(_ newItems: [Fruit]) {
    // 过滤掉已经存在的项
    let uniqueItems = newItems.filter { !fruits.contains($0) }
    fruits.append(contentsOf: uniqueItems)
    updateDataSource()
}

func updateDataSource() {
    var snapshot = NSDiffableDataSourceSnapshot<Section, Fruit>()
    snapshot.appendSections([.main])
    snapshot.appendItems(fruits)
    dataSource.apply(snapshot, animatingDifferences: true)
}

原有调用逻辑替换为调用统一方法即可:

@objc func add2() {
    let fruit = Fruit(title: "Fruit: 1")
    addNewFruits([fruit])
}

// 接口拉取完成的回调里,直接传入接口返回的数组
func loadRemoteFruits() {
    api.getFruitList { [weak self] result in
        guard let remoteList = try? result.get() else { return }
        self?.addNewFruits(remoteList)
    }
}

@objc func didTapAdd() {
    let actionSheet = UIAlertController(title: "Select Fruit", message: nil, preferredStyle: .actionSheet)
    actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    actionSheet.addAction(UIAlertAction(title: "Fruit 1", style: .default, handler: { [weak self] _ in
        let fruit = Fruit(title: "Fruit: 1")
        self?.addNewFruits([fruit])
    }))
    present(actionSheet, animated: true)
}

3. DiffableDataSource适配说明

UITableViewDiffableDataSource本身会根据模型的Hashable实现自动判断数据同一性,只要模型的判等逻辑符合业务规则,哪怕直接传入全量数据,系统也会自动计算差异,不会出现重复展示、UI刷新异常的问题。
如果接口返回的是全量最新数据(包含删除、内容修改的项),直接替换本地数组后全量应用snapshot即可,不需要手动计算差量。

场景扩展
  • 如果业务上允许同名但属性不同的项(比如同名但规格、价格不同),把所有参与唯一判断的字段都加入==和hash方法即可,核心原则是:业务上判定为同一项的两个对象,参与判等的字段必须完全一致;业务上不同的项,判等字段必须存在差异。
  • 如果需要同时展示本地新增未上传、服务端下发的同名项,可以给模型增加来源标识字段,判等时同时判断唯一ID+来源,避免不同来源的同项被错误过滤。

内容的提问来源于stack exchange,提问作者stompy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 00:45:36