08@理解“物件等同性”這一概念

Zack_Go發表於2019-01-05
  • 若想檢測物件的等同性,請提供isEqual:hash方法
  • 相同的物件必須具有相同的雜湊碼,但是兩個雜湊碼相同的物件卻未必相同
  • 不要盲目的逐個檢測每條屬性,而是應該依據具體需求來指定檢查方案。
  • 編寫hash方法時,應該使用計算速度快而且雜湊碼碰撞機率低的演算法。

1、isEqual方法與==區別

NSString *foo = @"Badger 123";
NSString *bar = [NSStringstringWithFormat:@"Badger %i", 123];
BOOL eaualA = (foo == bar); // NO
BOOL equalB = [foo isEqual: bar]; // YES
BOOL equalC = [foo isEqualToString: bar]; // YES
複製程式碼

區別:

  • ==比較的是兩個物件的指標本身,而不是其所指的物件。
  • NSObject協議中宣告isEqual來判斷物件等同性
  • 某些特殊物件提供了特殊的“等同性判定方法”。例如isEqualToString,推薦使用此方法。

2、isEqualhash方法

-(BOOL)isEqual:(id)object;
-(NSUInterger)hash;
複製程式碼

NSObject物件中這兩個方法的預設實現是:當且僅當“指標值”相等時,這兩個物件才相等。

EOCPerson類的自定義覆寫

-(BOOL)isEqual:(id)object {
    // 1、檢查指標是否相等
    if (self == object) return YES;
    // 2、判斷型別是否相等
    if ([self class] != [object class]) return NO;
    
    // 3、判斷屬性是否相等
    EOCPerson *otherPerson = (EOCPerson *)object
    ......
    
    return YES;
}

/// 推薦hash方法的寫法. YYAsyncLayer也是這種寫法。
-(NSUInteger)hash {
    NSUInteger firlstNameHash = [_firstName hash];
    NSUInteger lastNameHash = [_lastName hash];
    NSUnteger ageHash = _age;
    return firstNameHash ^ lastNameHash ^ ageHash;
}

複製程式碼

3、特定類具有等同性判定方法

無需檢測引數型別,程式碼如下

// 覆寫isEqual方法
-(BOOL)isEqual:(id)object{
    if ([self class] == [object class]) {
        return [self isEqualToPerson:(EOCPerson*)object];
    }else {
        return [super isEqual: object]
    }
}
-(BOOL)isEqualToPerson:(EOCPerson*)otherPerson {
    if (self == object) return YES;
    if (![_firstName isEqualToString:otherPerson.firstName]) {
        return NO;
    }
    ... 其他屬性判斷
    return YES;
}

複製程式碼

4、等同性判定的執行深度

NSArray的深度等同性判定,特定類的主鍵欄位判定。

5、容器中可變類的等同性

某個物件放入collection之後就不應該在改變雜湊碼。collection會把各個物件按照其雜湊碼分裝到不同的“箱子陣列”中。

相關文章