阅读 115

使用Swift Set放入重写了isEqual方法的OC对象的注意点

  • 需求:多个不同的OC对象,如果属性值一样的只需要一个。
  • 实现方案:
    1. 重写OC对象的isEqual方法(判断所有属性值是否都相等,相等返回true),
    2. 使用Set进行过滤(将OC对象放入Set,过滤重复的元素)。
  • 需求背景:由于项目最初是由OC编写,而新需求的代码要求都用Swift,因此才会有使用Swift的Set放入OC对象的情景。
  • 问题:重写了isEqual的OC对象放入Swift的Set中,相同的对象会重复放入,有一定几率发生崩溃。

解决方案:

第一步:重写OC对象的hash方法

默认的hash方法返回的是对象的内存地址,重写的isEqual方法:

image.png

如果不重写,多个【属性值一样的不同对象】有一定几率(不是每次都会)能放入Set。

🌰 🌰 🌰 尝试过疯狂插入【属性值一样的不同对象】,期望是不会重复插入只会插入一个,然而还是能插入重复的,不过最多也就只能”重复“插入3个: image.png 至于为什么会这样,由于本人才疏学浅,还不得而知,有望友人指导。

因此不重写是满足不了需求的,重写hash方法就是为了保证【属性值一样的不同对象】的hash值能相同。

比较推荐的写法:

image.png

使用在isEqual方法中用到的属性,根据属性值生成唯一的hash值。参考自:iOS中isEqual和Hash的笔记(一)

第二步:OC对象放入Set后,确保不会再修改这些(重写的hash方法中用到的属性)属性值

因为如果修改了属性值,新的hash值就会跟上一次放入时不一样。

如果【同一个对象】修改后有重复放入的操作,有一定几率(不是每次都会)无法过滤,导致元素重复导入。

🌰 🌰 🌰 放入了一个对象,然后修改这个对象的属性值,再重新放入,有一定几率会重复放入:

image.png

这样就不是正确期望的结果了,如果是OC的NSSet不会报错,但Swift的则会直接崩溃:

image.png

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方法。

文章分类
iOS
文章标签