iOS中的對象等同性

歡迎到我的 個人博客 http://liumh.com 瀏覽此文

使用 == 比較 iOS 中的對象時风纠,比較的是對象的指針。例如有如下比較時:

NSString *str = @"origin1";
NSString *strCopy = [str copy];
NSString *str1 = [NSString stringWithFormat:@"origin%@", @1];
    
BOOL equalA = (str == strCopy);
BOOL equalB = (str == str1);

BOOL equalC = [str isEqualToString:str1];  /**< equalC is YES */
BOOL equalD = [str isEqual:str1]; /**< equalD is YES */

equalA 的值會是 YES, 而 equalB 的值會是 NO牢贸,雖然 str竹观、str1潜索、strCopy 指針所指的對象的值都是 origin1

比較對象時竹习,我們應該使用 NSObject 協(xié)議中聲明的 isEqual: 方法來判斷兩個對象的等同性誊抛。一般來說,兩個類型不同的對象總是不相等的整陌。

NSObject 協(xié)議中有兩個判斷對象等同性的關鍵方法:

- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;

NSObject 對這兩個類的默認實現(xiàn)是:當且僅當其 “指針值” 完全相等時,這兩個對象才相等泌辫。若想在自定義對象中正確覆寫這兩個方法随夸,那么就必須先理解其約定: 如果 isEqual: 方法判斷兩個對象相等,那么其 hash 方法必須返回同一個值宾毒,但是如果兩個對象的 hash 方法返回同一個值,isEqual: 方法未必會認為二者相等殿遂。

假如有如下類:

@interface ACLStudent : NSObject

@property (nonatomic, assign, readonly) NSUInteger studentId;
@property (nonatomic, copy, readonly) NSString *firstName;
@property (nonatomic, copy, readonly) NSString *lastName;

@end

對于這樣的自定義對象伍俘,可以像 NSString- (BOOL)isEqualToString:(NSString *)aString 方法一樣,創(chuàng)建一個屬于該類的特定等同性方法癌瘾。同時需要注意該類對象的使用場景觅丰,例如這里,我們在判定兩個類對象是否相等時妨退,不需要對象中的所有字段都判定相等,只需要其 studentId 相等就可判定兩個對象表示的是同一個學生對象咬荷。方法實現(xiàn)像下面這樣:

- (BOOL)isEqualToStudent:(ACLStudent *)student {
    if (self == student) {
        return YES;
    }
    
    if (self.studentId == student.studentId) {
        return YES;
    }
    return NO;
}

建議同時實現(xiàn)其 isEqual: 方法冠句,像下面這樣:

- (BOOL)isEqual:(id)object {
    if (self == object) {
        return YES;
    }
    
    if ([self class] == [object class]) {
        return [self isEqualToStudent:object];
    } else {
        return [super isEqual:object];
    }
}

首先比較其指針值幸乒,假如指針值相等懦底,則對象相等罕扎,然后判斷傳入對象的類型聚唐,如果是類的類型腔召,則調(diào)用類特定的等同性方法杆查,否則交由父類來判斷臀蛛。

同時不要忘記覆寫 - (NSUInteger)hash 方法:

- (NSUInteger)hash {
    return self.studentId;
}

在覆寫類的 hash 方法時亲桦,要注意其有較高的執(zhí)行效率浊仆,又能使生成的哈希碼至少位于一定的范圍內(nèi),不至于頻繁的重復抡柿。編寫 hash 方法時舔琅,可用當前的對象做實驗,以便在減少哈希碼碰撞頻度與降低其運算復雜度之間取舍沙绝。

假如類的 hash 方法計算值過于頻繁的重復鼠锈,在 collection 中使用這種對象將會產(chǎn)生性能問題闪檬,因為 collection 在檢索哈希表時购笆,會用對象的哈希碼做索引粗悯。假如某個 collection 是用 set 實現(xiàn)的同欠,那么 set 可能會根據(jù)哈希碼把對象分裝到不同的數(shù)組中横缔。在向 set 中添加新對象時,要根據(jù)哈希碼找到與之相關的那個數(shù)組衫哥,依次檢查其中的各個元素茎刚,看數(shù)組中已有的對象是否和將要添加的對象相等。如果相等膛锭,那就說明要添加的對象已經(jīng)在 set 中了。由此可知蚊荣,如果令每個對象的都返回相同的哈希碼初狰,那么在 set 中已有 1000000 個對象的情況下互例,若是繼續(xù)向其中添加對象奢入,則需要將這 1000000 個對象全部掃描一遍媳叨。

例如下面兩種實現(xiàn)方法, 方法1:

- (NSUInteger)hash {
    NSString *stringToHash = [NSString stringWithFormat:@"%@:%@:%@", @(self.studentId), self.firstName, self.lastName];
    return [stringToHash hash];
}

方法2:

- (NSUInteger)hash {
    NSUInteger firstNameHash = [self.firstName hash];
    NSUInteger lastNameHash = [self.lastName hash];
    return firstNameHash ^ lastNameHash ^ self.studentId;
}

方法2 比 方法1 更好腥光,減少了創(chuàng)建字符串的開銷肩杈,同時其哈希值不至于頻繁重復柴我。

注意扩然,我們把對象放入 collection 之后,就不應再改變其哈希碼了夫偶。前面講過界睁,collection 會把各個對象按照其哈希碼分裝到不同的"箱子數(shù)組"中。如果某個對象在放入"箱子"之后哈希碼又變了兵拢,那么其現(xiàn)在所處的箱子對它來說是"錯誤"的。要解決這個問題说铃,需要確保哈希碼不是根據(jù)對象的“可變部分”(mutable portion)計算出來的访惜,或者保證放入 collection 之后就不再改變對象的內(nèi)容了。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末债热,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子幼苛,更是在濱河造成了極大的恐慌窒篱,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件墙杯,死亡現(xiàn)場離奇詭異,居然都是意外死亡高镐,警方通過查閱死者的電腦和手機溉旋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來避消,“玉大人,你說我怎么就攤上這事岩喷∷∧” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵婶溯,是天一觀的道長。 經(jīng)常有香客問我偷霉,道長迄委,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任叙身,我火速辦了婚禮,結果婚禮上硫狞,老公的妹妹穿的比我還像新娘信轿。我一直安慰自己残吩,他們只是感情好财忽,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布泣侮。 她就那樣靜靜地躺著即彪,像睡著了一般活尊。 火紅的嫁衣襯著肌膚如雪隶校。 梳的紋絲不亂的頭發(fā)上蛹锰,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音宁仔,去河邊找鬼稠屠。 笑死峦睡,一個胖子當著我的面吹牛翎苫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播煎谍,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼攘蔽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了呐粘?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤作岖,失蹤者是張志新(化名)和其女友劉穎唆垃,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辕万,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年沉删,在試婚紗的時候發(fā)現(xiàn)自己被綠了渐尿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矾瑰。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡砖茸,死狀恐怖殴穴,靈堂內(nèi)的尸體忽然破棺而出凉夯,到底是詐尸還是另有隱情推正,我是刑警寧澤恍涂,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布植榕,位于F島的核電站再沧,受9級特大地震影響尊残,放射性物質發(fā)生泄漏炒瘸。R本人自食惡果不足惜寝衫,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一顷扩、第九天 我趴在偏房一處隱蔽的房頂上張望慰毅。 院中可真熱鬧隘截,春花似錦、人聲如沸婶芭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惰赋。三九已至呵哨,卻和暖如春赁濒,著一層夾襖步出監(jiān)牢的瞬間孟害,已是汗流浹背拒炎。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工挨务, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留枝冀,地道東北人耘子。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓果漾,卻偏偏與公主長得像谷誓,于是被迫代替她去往敵國和親绒障。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容