- 需求:多个不同的OC对象,如果属性值一样的只需要一个。
- 实现方案:
- 重写OC对象的isEqual方法(判断所有属性值是否都相等,相等返回true),
- 使用Set进行过滤(将OC对象放入Set,过滤重复的元素)。
- 需求背景:由于项目最初是由OC编写,而新需求的代码要求都用Swift,因此才会有使用Swift的Set放入OC对象的情景。
- 问题:重写了isEqual的OC对象放入Swift的Set中,相同的对象会重复放入,有一定几率发生崩溃。
解决方案:
第一步:重写OC对象的hash方法
默认的hash方法返回的是对象的内存地址,重写的isEqual方法:
如果不重写,多个【属性值一样的不同对象】有一定几率(不是每次都会)能放入Set。
? ? ? 尝试过疯狂插入【属性值一样的不同对象】,期望是不会重复插入只会插入一个,然而还是能插入重复的,不过最多也就只能”重复“插入3个:
至于为什么会这样,由于本人才疏学浅,还不得而知,有望友人指导。
因此不重写是满足不了需求的,重写hash方法就是为了保证【属性值一样的不同对象】的hash值能相同。
比较推荐的写法:
使用在isEqual方法中用到的属性,根据属性值生成唯一的hash值。参考自:iOS中isEqual和Hash的笔记(一)
第二步:OC对象放入Set后,确保不会再修改这些(重写的hash方法中用到的属性)属性值
因为如果修改了属性值,新的hash值就会跟上一次放入时不一样。
如果【同一个对象】修改后有重复放入的操作,有一定几率(不是每次都会)无法过滤,导致元素重复导入。
? ? ? 放入了一个对象,然后修改这个对象的属性值,再重新放入,有一定几率会重复放入:
这样就不是正确期望的结果了,如果是OC的NSSet不会报错,但Swift的则会直接崩溃:
Fatal error: Duplicate elements of type 'JPDog' were found in a Set.
This usually means either that the type violates Hashable's requirements,
or that members of such a set were mutated after insertion.
致命错误:在集合中发现类型为“JPDog”的重复元素。
这通常意味着类型违反了Hashable的要求,或者这种集合的成员在插入后发生了变异。
复制代码
从崩溃信息看得出,Swift的Set应该是不能放入两个地址一样(同一个)对象。
总结:Swift的Set如果要放入重写了isEqual方法的OC对象,那就最好按照第一步的方式(根据属性值)重写它的hash方法,另外要保证放入后不会再修改isEqual和hash方法中用到的属性值。
如果之后很有可能会改变这些属性值,个人建议创建一个新的NSObject类去包裹这个类,让Set存入这个新类,放入时保存这些属性值,然后按照一样的方式重写这个新类的isEqual和hash方法。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END