如何为枚举的.loading case生成唯一标识符适配RxDataSources?
解决方案:RxDataSources中多Loading实例的IdentifiableType兼容问题
RxDataSources的差异计算依赖IdentifiableType提供的唯一identity,多个.loading实例共用同一个id会导致Diffing算法无法区分实例,进而引发UI更新异常。以下是几种可行的解决思路:
方案一:为Loading实例添加唯一标识关联值
通过给.loading case添加唯一ID关联值,确保每个Loading实例拥有独立的identity,这是最通用的解决方案。
修改后的枚举代码:
enum ViewModelType: Equatable, IdentifiableType { case loading(id: String) case post(Post) var identity: String { switch self { case .loading(let id): return id case let .post(post): return String(post.id) } } static func == (lhs: ViewModelType, rhs: ViewModelType) -> Bool { switch (lhs, rhs) { case (.loading(let lId), .loading(let rId)): return lId == rId case let (.post(l), .post(r)): return l == r default: return false } } }
使用时生成唯一ID(推荐用UUID):
// 创建多个独立的Loading实例 let loadingItems = [ ViewModelType.loading(id: UUID().uuidString), ViewModelType.loading(id: UUID().uuidString), ViewModelType.loading(id: UUID().uuidString) ]
优点:完全符合RxDataSources的要求,Diffing算法能准确计算每个实例的增删改操作;缺点:创建Loading实例时需要额外生成ID,代码量略有增加。
方案二:用序号作为Loading实例的标识
如果Loading实例的数量和位置是可控的(比如固定位置的加载项),可以用序号作为唯一标识,避免生成UUID的开销。
修改后的枚举代码:
enum ViewModelType: Equatable, IdentifiableType { case loading(index: Int) case post(Post) var identity: String { switch self { case .loading(let index): return "loading_\(index)" case let .post(post): return String(post.id) } } static func == (lhs: ViewModelType, rhs: ViewModelType) -> Bool { switch (lhs, rhs) { case (.loading(let lIdx), .loading(let rIdx)): return lIdx == rIdx case let (.post(l), .post(r)): return l == r default: return false } } }
使用时指定序号:
let loadingItems = [ ViewModelType.loading(index: 0), ViewModelType.loading(index: 1), ViewModelType.loading(index: 2) ]
优点:轻量高效,无需额外生成UUID;缺点:仅适用于Loading位置固定或序号可维护的场景,动态调整Loading数量时需要同步更新序号。
方案三:用单个实例表示多个Loading状态
如果业务上不需要单独控制每个Loading实例,可以将多个Loading合并为一个带数量参数的case,在UI层渲染对应数量的加载单元格。
修改后的枚举代码:
enum ViewModelType: Equatable, IdentifiableType { case loading(count: Int) case post(Post) var identity: String { switch self { case .loading: return "loading_group" case let .post(post): return String(post.id) } } static func == (lhs: ViewModelType, rhs: ViewModelType) -> Bool { switch (lhs, rhs) { case (.loading(let lCount), .loading(let rCount)): return lCount == rCount case let (.post(l), .post(r)): return l == r default: return false } } }
UI层处理逻辑:收到.loading(count: 3)时,循环渲染3个加载单元格即可。
优点:模型结构更简洁,无需维护多个Loading实例;缺点:灵活性不足,无法单独控制单个Loading实例的状态变化。
内容的提问来源于stack exchange,提问作者Florian Ldt
相关产品推荐
相关产品推荐

