Swift并发中Task的hashValue是否具备唯一性?
关于用Task的hashValue作为唯一标识的可靠性分析
直接给结论:用Task的hashValue作为主键做数组去重,在唯一性和内存层面都没有保障,具体原因和替代方案如下:
1. hashValue不具备全局唯一性
Swift里所有遵守Hashable协议的类型,hashValue的作用只是提升哈希表(比如Set、Dictionary)的查找效率,完全不保证不同实例的hashValue绝对唯一——哈希碰撞是哈希算法的固有特性,哪怕两个Task是内存中完全独立的不同对象,也有可能生成相同的hashValue。用它当主键去重,会有概率误删不同的Task实例。
2. 内存层面的实例身份判断不能依赖hashValue
如果你的需求是移除数组中同一个内存实例的Task,正确方式是用Swift的身份运算符===,它直接比较对象的内存地址,能精准识别是否为同一个实例。而hashValue和内存地址没有绑定关系:相同hashValue的对象可能在不同内存地址,不同地址的对象也可能有相同hashValue。
3. 可行的替代方案
方案一:基于实例身份去重
如果要确保只移除数组中重复的同一个Task实例,可以遍历数组用===判断:
var taskArray: [SomeProtocol] = [] // 去重逻辑:保留首次出现的实例,移除后续重复实例 var uniqueTasks: [SomeProtocol] = [] for task in taskArray { guard let taskInstance = task as? Task else { continue } if !uniqueTasks.contains(where: { ($0 as? Task) === taskInstance }) { uniqueTasks.append(task) } } taskArray = uniqueTasks
方案二:用真正的唯一标识代替hashValue
如果需要业务层面的唯一主键,建议给Task添加初始化时生成的唯一ID,比如UUID:
protocol SomeProtocol { var taskId: String { get } } extension Task: SomeProtocol { var taskId: String { return self.uuid.uuidString } } // 给Task添加UUID属性,初始化时自动生成 class Task { let uuid = UUID() // 其他业务属性与逻辑 }
UUID的碰撞概率极低,几乎可以忽略,完全能作为可靠的唯一主键用于去重。
内容的提问来源于stack exchange,提问作者dev Crying
相关产品推荐
相关产品推荐

