Objective-C——判斷對象等同性

對象等同性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中就會有兩個相等的元素存在!

相關文章
相關標籤/搜索