第 8 條:理解“對象等同性”這一概念

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

主要來源:《Effective Objective-C 2.0》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容