重載hash與isEqual:方法

前言
NSObject 自帶了hash與isEqual:方法,服務於具有hash表結構的數據結構。NSObject自帶的hash函數相當於hash表中的f(key)函數中的key,這“唯一”的key需要用戶自己產生,至於用什麼算法由用戶自己決定。
准備
// // Model.h // Hash // // Created by YouXianMing on 16/4/15. // Copyright © 2016年 YouXianMing. All rights reserved. // #import <Foundation/Foundation.h> @interface Model : NSObject <NSCopying> @property (nonatomic, strong) NSString *firstName; @property (nonatomic, strong) NSString *lastName; @end
//
// Model.m
// Hash
//
// Created by YouXianMing on 16/4/15.
// Copyright © 2016年 YouXianMing. All rights reserved.
//
#import "Model.h"
#define NSUINT_BIT (CHAR_BIT * sizeof(NSUInteger))
#define NSUINTROTATE(val, howmuch) ((((NSUInteger)val) << howmuch) | (((NSUInteger)val) >> (NSUINT_BIT - howmuch)))
@implementation Model
- (id)copyWithZone:(nullable NSZone *)zone {
Model *result = [[[self class] allocWithZone:zone] init];
result.firstName = self.firstName;
result.lastName = self.lastName;
return result;
}
- (NSUInteger)hash {
return NSUINTROTATE([_firstName hash], NSUINT_BIT / 2) ^ [_lastName hash];
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if ([object isKindOfClass:[Model class]]) {
return [self hash] == [object hash];
} else {
return NO;
}
}
@end
測試
1. 測試對象是否相同(注意打印信息)

之所以會相同是因為兩個對象的hash算法以屬性值的唯一性來確保對象的差異性,也就是說,只要兩個對象屬性值一致,那這兩個對象的就是相等的。

2. 測試字典setObject:forKey:方法(注意打印信息)

字典通過modelB對象作key值竟然找到了modelA作為key值時存儲的值,這是因為我們已經讓modelA與modelB“相等了”,可以參考測試1。
字典在設置key值的時候是需要復制這個key值對象的(這個key值對象需要實現NSCopying協議),也就是說,我們的modelA在作為key值的時候已經被字典復制一份了,因為字典需要確保這個key值不可變,否則,做為key值的對象通過修改內部屬性而導致了這個對象的hash值發生變化,會出現找不到對象的情況。


大家可以觀察一下斷點流程(字典先獲取外部對象的hash值,然後與自己的key值對象進行比較執行isEqual:方法,如果認為比較結果一致,就確保是同一個對象)

字典在執行setObject:forKey:方法的時候,會先執行這個key值對象的hash方法用以生成一個鍵值,然後再copy這個key值對象。

3. 測試NSSet的addObject:方法(注意打印信息)

addObject:方法執行的流程如下:先獲取對象modelA的hash值,再添加modelB的時候獲取modelB的hash值,然後進行比較,如果兩者的比較結果一致,則認為這是相同的對象。
