0x00 前言
今天看到了這篇文章iOS開發(fā) 之 不要告訴我你真的懂isEqual與hash!,覺得很有意思,但是又對(duì)于里面的一部分內(nèi)容理解不了,就自己建了demo試了下然后趁熱打鐵寫篇博客記錄下。
0x01 總結(jié)
先寫下我看了這篇文章的總結(jié):
- 1.
==用于比較對(duì)象地址,如果不一致返回NO。 - 2.
isEqual用于比較對(duì)象地址,但是可以重寫,自定義判斷邏輯。 - 3.
hash不常用,在往NSSet添加對(duì)象時(shí)會(huì)用到。 - 4.3的具體邏輯是:在add時(shí),系統(tǒng)會(huì)調(diào)用
hash,如果返回值和集合里的一致,就會(huì)判斷集合內(nèi)已存在該對(duì)象,不給加。如果不一致,再調(diào)用isEqual方法判斷。 - 如果要重寫
hash,直接return [super hash]是不對(duì)的。因?yàn)榉祷氐氖菍?duì)象地址。這樣會(huì)導(dǎo)致兩個(gè)不同的對(duì)象永遠(yuǎn)加入不到同一個(gè)set里面。
0x02 例子
下面是一些測(cè)試?yán)?,我?chuàng)建了Person類,有name屬性,我會(huì)重寫isEqual和hash方法來測(cè)試。
1.==和isEqual方法,isEqual未重寫
Person *person1 = [[Person alloc] init];
person1.name = @"1";
Person *person2 = [[Person alloc] init];
person2.name = @"1";
NSLog(@"%d", person1==person1);
NSLog(@"%d", person1==person2);
NSLog(@"%d", [person1 isEqual:person1]);
NSLog(@"%d", [person1 isEqual:person2]);
2020-03-07 14:06:48.004179+0800 AnimateDemo[43855:5522556] 1
2020-03-07 14:06:48.004259+0800 AnimateDemo[43855:5522556] 0
2020-03-07 14:06:48.004322+0800 AnimateDemo[43855:5522556] 1
2020-03-07 14:06:48.004391+0800 AnimateDemo[43855:5522556] 0
2.==和isEqual方法,isEqual重寫
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[Person class]]) {
return NO;
}
if ([((Person *)object).name isEqualToString:self.name]) {
return YES;
} else {
return NO;
}
}
Person *person1 = [[Person alloc] init];
person1.name = @"1";
Person *person2 = [[Person alloc] init];
person2.name = @"1";
NSLog(@"%d", person1==person1);
NSLog(@"%d", person1==person2);
NSLog(@"%d", [person1 isEqual:person1]);
NSLog(@"%d", [person1 isEqual:person2]);
2020-03-07 14:23:33.606430+0800 AnimateDemo[43916:5530391] 1
2020-03-07 14:23:33.606498+0800 AnimateDemo[43916:5530391] 0
2020-03-07 14:23:33.606567+0800 AnimateDemo[43916:5530391] 1
2020-03-07 14:23:33.606639+0800 AnimateDemo[43916:5530391] 1
3.默認(rèn)hash調(diào)用
我重寫了hash的方法,然后NSSet里加對(duì)象
- (NSUInteger)hash {
NSUInteger superHash = [super hash];
NSLog(@"%ld", superHash);
return superHash;
}
Person *person1 = [[Person alloc] init];
person1.name = @"1";
Person *person2 = [[Person alloc] init];
person2.name = @"1";
NSMutableSet *set = [NSMutableSet set];
[set addObject:person1];
[set addObject:person2];
NSLog(@"set count = %ld", set.count);
2020-03-07 14:28:55.113639+0800 AnimateDemo[43956:5534222] 105553148183088
2020-03-07 14:28:55.113703+0800 AnimateDemo[43956:5534222] 105553148183104
2020-03-07 14:28:55.113764+0800 AnimateDemo[43956:5534222] set count = 2
說明hash方法被調(diào)用了。
但是如果我不想將兩個(gè)我認(rèn)為一樣的對(duì)象加入到set里面怎么辦呢?比如例子中的兩個(gè)person對(duì)象,我認(rèn)為他們是一樣的。
那么,重寫hash并返回[super hash]是做不到的。因?yàn)椴煌瑢?duì)象的[super hash]返回的都不相同。
那么要怎么做呢?
4.正確的hash重寫方法
- (NSUInteger)hash {
NSUInteger nameHash = self.name.hash;
NSLog(@"%ld", nameHash);
return nameHash;
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[Person class]]) {
return NO;
}
if ([((Person *)object).name isEqualToString:self.name]) {
return YES;
} else {
return NO;
}
}
Person *person1 = [[Person alloc] init];
person1.name = @"1";
Person *person2 = [[Person alloc] init];
person2.name = @"1";
NSMutableSet *set = [NSMutableSet set];
[set addObject:person1];
[set addObject:person2];
NSLog(@"set count = %ld", set.count);
2020-03-07 14:39:05.182269+0800 AnimateDemo[44016:5540023] 918
2020-03-07 14:39:05.182339+0800 AnimateDemo[44016:5540023] 918
2020-03-07 14:39:05.182412+0800 AnimateDemo[44016:5540023] set count = 1
正確的方法是用return self.name.hash;。
但是光有hash還不夠,還需要重寫isEqual方法。原因上面已經(jīng)說了,set addObject方法會(huì)先去比較hash,在去比較isEqual。