對象等同性判斷

對象等同性

概述

在實際的開發過程中,常常須要比較對象是否相同。可是,==操做符比較出來的結果可能並非想要的,由於這個操做符比較的是指針自己,並非對象。因此大部分狀況下,比價對象應該使用NSObject協議中的isEqual:c++

  • 通常來講,類型不一樣的對象老是不相等的。
  • 某些類會提供本身的等同性斷定方法。

好比:數據庫

NSString *foo = @"Student 123";
NSString *bar = [NSString stringWithFormat:@"Student %i",123];
BOOL equalA = (foo == bar); //equalA = NO
BOOL equalB = [foo isEqaul:bar]; //equalA = NO
BOOL equalC = [foo isEqualToString:bar]; //equalC = YES
複製代碼

這裏能夠看出,NSString有着本身的等同性判斷方法isEqualToString:。調用這個方法會比調用isEqual:方法快,由於後者須要執行額外的步驟檢測受測對象的類型。數組

判斷過程

判斷對象等同性在NSObject協議中有兩個關鍵方法:bash

- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;
複製代碼

這兩個方法的默認實現是兩個對象內存地址徹底(指針值)相等時,這兩個對象才相等。在自定義對象中,正確重寫這兩個方法的步驟應該是:性能

重寫isEqual:返回YES --> Hash值相等 --> 調用isEqual:方法判斷對象等同
複製代碼

舉例

@interface EOCPerson : NSObject
@property (nonatomic, copy)NSString *firstName;
@property (nonatomic, copy)NSString *lastName;
@property (nonatomic, assign)NSUInteger *age;
@end
複製代碼

很明顯,當這個對象全部字段都相同時,就能夠認定兩個對象相等了。因此重寫isEqual:方法:優化

- (BOOL)isEqual:(id)object {
    ///判斷指針相等
    if (self == object) return YES;
    ///不一樣類不相等
    if ([self class] != [object class]) return NO;
    
    
    EOCPerson *otherPerson = (EOCPerson*)object;
    if (![_firstName isEqualToString:otherPerson.firstName]) {
        return NO;
    }
    if (![_lastName isEqualToString:otherPerson.lastName]) {
        return NO;
    }
    if (_age != otherPerson.age) {
        return NO;
    }
    return YES;
}
複製代碼

首先判斷了指針是否相等,以後判斷所屬的類。不過在判斷類的時候,須要特別注意有繼承的狀況,若是判斷子類是否與父類相等,就不能這麼粗暴的重寫isEqual方法了,須要根據狀況,自定義一個子類和父類的比較規則。atom

以後就須要實現hash方法了,最早想到的是這樣:spa

- (NSUInterger)hash {
    return 1024;
}
複製代碼

這樣實現以後確實能實現兩個EOCPerson對象的等同性判斷了。但在一些場景中會產生性能問題。好比一個用set實現的collection,collocation在檢索哈希表時,會用哈希值做爲索引。每次向collection添加新對象時,優先會檢查哈希值相同的相關對象,再判斷等同性。因此,若是已經有了10000個對象在set中,此時添加一個新對象,按照上個例子中的實現,就須要遍歷完10000個對象才能完成插入對象的操做。指針

那麼咱們將上述例子作一下改進:code

- (NSUInterger)hash {
    NSString *stringToHash = [NSString stringWithFormat:@"%@:%@:%i", _firstName, _LastName, _age];
    return [stringToHash hash];
}
複製代碼

這麼作就能避免剛纔所說的問題了,提升set操做時的檢索效率,但字符串操做相對返回一個單一值來講仍然是一個耗時過程,會影響set的性能。

再進一步的優化一下:

- (NSUInterger)hash {
    NSUInterger firstNameHash = [_firstName hash];
    NSUInterger lastNameHash = [_lastName hash];
    NSUInterger ageHash = _age;
    return firstNameHash ^ lastNameHash ^ ageHash;
}
複製代碼

這樣既解決了哈希索引的問題,有提升了哈希值生成的效率。因此哈希值的生成有兩個注意點:

  • 減小碰撞頻率
  • 下降運算複雜度

等同性執行深度

在判斷數組的是否等同的時候,須要判斷數組內全部對象都相同,咱們把這個叫作「深度等同性判斷」。但有時候,根據不一樣的場景,不須要判斷全部對象或者對象的全部屬性都同樣,這樣就能夠下降等同性判斷的執行深度。

好比數組的數據是從數據庫裏取出的,這個時候只要判斷數據對象對應的主鍵是否相等,便能判斷這個對象的等同性。

相關文章
相關標籤/搜索