對象等同性atom
不管咱們使用什麼語言,老是會出現須要判斷兩個對象是否相等的狀況,OC固然也不例外。首先看一段代碼:spa
NSString *str1 = [[NSString alloc] initWithCString:"equal" encoding:NSUTF8StringEncoding]; NSString *str2 = @"equal"; if(str1 == str2) { NSLog(@"equal"); }
很明顯,在咱們開來,str1和str2是「相等的」。可是事實上equal是不會被打印的。這是由於若是咱們直接比較兩個對象是否相等,實際上比較的是兩個對象的指針是否相等。指針
上述代碼中str1和str2是分別指向兩塊不一樣的內存的,因此確定不會像等了。code
咱們稍微修改一下代碼再看看:對象
NSString *str1 = [[NSString alloc] initWithCString:"equal" encoding:NSUTF8StringEncoding]; NSString *str2 = @"equal"; if([str1 isEqual:str2]) { NSLog(@"equal"); }
注意看加粗語句,咱們改用NSObject提供的isEqual方法比較,發現"equal"被打印了出來。由於isEqual在NSString 內部被實現的時候比較的是真正的字符串是否相等!blog
對象等同性實現內存
看過上面例子後,如今咱們本身建立一個類來進一步說明等同性字符串
#import <Foundation/Foundation.h> @interface EqualObject : NSObject @property(nonatomic ,strong)NSString *name; @end #import "EqualObject.h" @implementation EqualObject @end
定義了一個EqualObject類,有一個name屬性。hash
如今咱們建立兩個對象來比較一下:it
EqualObject *object1 = [EqualObject new]; EqualObject *object2 = [EqualObject new]; if([object1 isEqual:object2]) { NSLog(@"equal"); }
發現代碼運行結束並無輸出"equal",緣由就在於isEqual方法是須要咱們本身實現的。NSObject的isEqual:方法默認是比較兩個對象指向的地址是否相等,這裏開闢了兩個對象確定不想等了。
如今咱們添加isEqual:方法的實現:
-(BOOL)isEqual:(id)object { if([self class] == [object class]) { if(![self.name isEqual:[(EqualObject *)object name]]) { return NO; } return YES; } else { return [super isEqual:object]; } }
這裏稍微解釋一下,爲何兩個對象不一樣類就調用父類的isEqual:這是由於,有的時候咱們是可讓子類等於父類的,咱們只須要關注屬性是否相同時能夠這樣寫,若是不須要也能夠不在父類處理那麼久默認不相等了。
如今咱們不對name進行賦值操做依然是沒有值打印出來的。
修改客戶端代碼:
EqualObject *object1 = [EqualObject new]; EqualObject *object2 = [EqualObject new]; object1.name = @"xiaoming"; object2.name = @"xiaoming"; if([object1 isEqual:object2]) { NSLog(@"equal"); }
發現這時候在運行就已經相等了。
爲類定製等同性方法
咱們能夠看到NSString除了能夠用isEqual比較是否相等意外,還可使用isEqualToString來比較!這是專爲NSString類定製的等同性方法,提供這樣的方法就能夠很明確咱們實現了該對象的isEqual方法。
下面爲EqualObject提供定製的等同性方法,並修改isEqual:方法
- (BOOL)isEqualToEqualObject:(EqualObject *)object { if(self == object) return YES; if(![self.name isEqualToString:object.name]) return NO; return YES; } - (BOOL)isEqual:(id)object { if([self class] == [object class]) { return [self isEqualToEqualObject:object]; } else { return [super isEqual:object]; } }
而後客戶端修改
if([object1 isEqualToEqualObject:object2]) { NSLog(@"equal"); }
很順利的"equal"了...
對象hash碼
每個OC對象內部都是有一個hash碼的,當對象存入集合中(Array,Set,HashTable等),那麼他們的hash碼會被當作鍵來決定他們該放入哪個集合中。
首先咱們先看一下集合內部是如何存儲的
hashCode | subCollection |
code1 | value1,value2,value3,value4 |
code2 | value5,value6 |
code3 | value7 |
code4 | value8,value9,value10 |
集合的內部並不像咱們所想的那樣,是一個hash表,它將插入的對象根據hashCode來決定放入哪個子集合。若是要刪除或者比較集合內元素,它首先根據hashCode找到子集合,而後跟子集合的每一個元素比較。
因此若是咱們的對象的hashCode若是都相同,那麼就會出現嚴重的效率問題,
理論上來講,咱們肯定等同性的兩個對象的hash應該是相同的而不等的兩個對象hash也應該不等,這樣在存入hashTable之類的集合時,就會避免相同對象的重複添加,好比咱們兩個對象hash相等,但實際對象不等,那麼添加的時候就會被添加到同一subCollection下面。
因此爲了不這種狀況,咱們儘可能本身實現一種避免重複的方式,
這裏提供一種,添加一個新屬性age,hash實現以下:
- (NSUInteger)hash { NSUInteger nameHash = [_name hash]; NSUInteger ageHash = _age; return nameHash ^ ageHash; }
集合中的對象等同性
咱們對NSArray調用isEqual方法,它會對集合裏的每一個對象和另外一個集合相同位置的對象進行isEqual:操做,只有所有相等,兩個集合才相等。
這裏說一下,集合裏面最後添加都是不可變元素,若是是可變性元素會出現不法控制的狀況。
好比咱們往NSSet裏面添加兩個NSMutableArray,一開始兩個array不等,那麼set中就有兩個元素。
而後修改一個array使兩個相等,這是set中就會有兩個相等的元素存在!