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