==
操作符比較的是兩個指針本身,而不是其所指的對象。應使用 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
方法時,應使用計算速度快且哈希碼碰撞幾率低的算法。