重載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值,然後進行比較,如果兩者的比較結果一致,則認為這是相同的對象。