==
操作符比较的是两个指针本身,而不是其所指的对象。应使用 NSObject
协议中声明的 isEqual:
方法来判断两个对象的等同性。
例如:
NSString *foo = @"Badger 123";
NSString *bar = [NSString stringWithFormat:@"Badger %i", 123];
BOOL equalA = (foo == bar); //< equalA = NO
BOOL equalB = [foo isEqual:bar]; //< equalB = YES
BOOL equalC = [foo isEqualToString:bar]; //< equalC = YES
NSObject
协议中有两个判断等同性的关键方法:
- (BOOL)isEqual:(id)object;
+ (NSUInteger)hash;
// 这两个方法的默认实现是:当且仅当其“指针值”(pointer value)完全相等时,两个对象才相等。
注意:若
isEqual:
方法判定两个对象相等,那么其hash
方法也必须返回同一个值;若两个对象的hash
方法返回同一个值,那么isEqual:
未必认为二者相等。
hash: 方法实现
/* 方法一 */
- (NSUInteger)hash {
return 1337;
}
/* 方法二 */
- (NSUInteger)hash {
NSString *stringToHash = [NSString stringWithFormat:@"%@:%@", _firstName, _lastName];
return [stringToHash hash];
}
/* 方法三 */
- (NSUInteger)hash {
NSUInteger firstNameHash = [_firstName hash];
NSUInteger lastNameHash = [_lastName hash];
return firstNameHash ^ lastNameHash; //按位异或
}
三种方法对比:
方法一:会产生性能问题。
方法二:创建字符串开销,添加到collection
也会有性能问题。
方法三:高效,哈希码在一定范围内,会碰撞。
特定类的等同性判断方法
NSString: isEqualToString:
NSArray: isEqualToArray:
NSDictionary: isEqualToDictionary:
自定义判断等同性方法:
- (BOOL)isEqualToPerson:(ViewController*)otherPerson {
if (self == otherPerson) return YES;
if (![_firstName isEqualToString:otherPerson.firstName]) {
return NO;
}
if (![_lastName isEqualToString:otherPerson.lastName]) {
return NO;
}
return YES;
}
// 重写“isEqual:”方法
- (BOOL)isEqual:(id)object {
if ([self class] == [object class]) {
return [self isEqualToPerson:(ViewController*)object];
} else {
return [super isEqual:object];
}
}
等同性判定执行深度
有时无需将所有数据逐个比较,只根据其中一部分数据即可判断二者是否等同。
容器中可变类的等同性
把某个对象放入 collection 之后,就不应再改变其哈希码了。
要点:
- 相同的对象必须有相同的哈希码,但哈希码相同的对象未必相同。
- 不要盲目地逐个检测每条属性,应依照具体需求来检测。
- 编写
hash
方法时,应使用计算速度快且哈希码碰撞几率低的算法。