iOS - 判断对象相等,重写isEqual,hash

it2023-10-09  68

一. ==

通常我们会用 == 来判断两个对象是否相等,但是这样比较出来的结果可能不是我们期望的,那么 == 究竟比较的是什么

对于基本类型==比较的是值对于对象类型,==比较的是对象的地址,即是否为同一个对象 NSString *s1 = @"123"; NSString *s2 = [NSString stringWithFormat:@"%d", 123]; BOOL e1 = s1 == s2; BOOL e2 = [s1 isEqual:s2]; NSLog(@"%d, %d", e1, e2);

运行结果:

0, 1

由于s1和s2不是同一个对象(即对象地址不同),所以==结果为0(NO),而isEqual方法则判断对象是否相同,所以结果为:0,1。

二.重写isEqual方法

一般我们会使用NSObject协议声明的isEqual方法来判断对象的等同性。 为了更好的进行深层次的比较,iOS系统中的NSObject子类还实现了各自的isEqual:方法。 对于自定义的类型来说,如果有判断对象是否相等需求,那么我们可以自行实现isEqual方法,具体步骤如下:

实现一个isEqualTo__ClassName__:方法来执行有意义的值比较.重写isEqual: 方法 来作类型和对象identity检查, 回调上述的值比较方法.重写 hash, 在集合中查找时最先调用(这个会在下一部分解释). 实例代码: person.h(定义person类) @interface Person : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *idStr; @property (nonatomic, strong) NSDate *birthday; //@property (readonly) NSUInteger hash; @end

person.m

#import "Person.h" @implementation Person //区分成员变量名称和属性名称。使用@synthesize可以改变_name名称 @synthesize name = _name; @synthesize idStr = _idStr; - (id) initWithName:(NSString *)name idStr: (NSString *) idStr { if(self = [super init]) { self.name = name; self.idStr = idStr; } return self; } //重写isEqual方法 - (BOOL)isEqual:(id)object { if(self == object) { return YES; } if(![object isKindOfClass:[Person class]]) { return NO; } return [self isEqualToPerson:(Person *)object]; } - (BOOL)isEqualToPerson:(Person *)person { if (!person) { return NO; } BOOL haveEqualNames = (!self.name && !person.name) || [self.name isEqualToString:person.name]; BOOL haveEqualBirthdays = (!self.birthday && !person.birthday) || [self.birthday isEqualToDate:person.birthday]; return haveEqualNames && haveEqualBirthdays; }

上述代码主要步骤如下

Step 1: ==运算符判断是否是同一对象, 因为同一对象必然完全相同 Step 2: 判断是否是同一类型, 这样不仅可以提高判等的效率, 还可以避免隐式类型转换带来的潜在风险 Step 3: 通过封装的isEqualToPerson方法, 提高代码复用性 Step 4: 判断person是否是nil, 做参数有效性检查 Step 5: 对各个属性分别使用默认判等方法进行判断 Step 6: 返回所有属性判等的与结果

三.isEqual和hash

对象相等是相互的([a isEqual:b] ⇒ [b isEqual:a])

如果对象相等,它们的hash值必须相等([a isEqual:b] ⇒ [a hash] == [b hash])

但是,反过来不一定成立:=如果它们的hash值相等,两个对象不一定相等。([a hash] == [b hash] ¬⇒ [a isEqual:b])

hash方法 hash值(用于查找集合中成员的位置标识), 通过hash方法计算得来, 且hash方法返回的hash值最好唯一

hash方法什么时候被调用? hash方法只在对象被添加至NSSet和设置为NSDictionary的key时会调用 NSSet添加新成员时, 需要根据hash值来快速查找成员, 以保证集合中是否已经存在该成员 NSDictionary在查找key时, 也利用了key的hash值来提高查找的效率

hash方法与isEqual的关系 为了优化判等的效率, 基于hash的NSSet和NSDictionary在判断成员是否相等时, 会先判断hash值是否相等,如果相等,那么就会进行isEqual的判断;反之,不相等,直接判断对象不相等 第一步: 集成成员的hash值是否和目标hash值相等, 如果相同进入Step 2, 如果不等, 直接判断不相等 第二步: hash值相同(即Step 1)的情况下, 再进行对象判等, 作为判等的结果 简单地说就是hash值是对象判等的必要非充分条件

如何重写hash方法

对于上面Person类的hash方法实现如下

- (NSUInteger)hash { return [self.name hash] ^ [self.birthday hash]; }

参考 参考文章2

最新回复(0)