OC 對(duì)象等同性

1约谈、什么是等同性

根據(jù)等同性來(lái)比較對(duì)象是一個(gè)非常有用的功能碗啄。我們常用的 ==操作符比較质和,但是==比較的是指針本身,而不是其所指的對(duì)象稚字。如果兩個(gè)對(duì)象指針不同饲宿,但是其它的所有屬性等全都相同厦酬,這兩個(gè)對(duì)象可以說(shuō)是等同的
常見(jiàn)的比較方法有NSString瘫想、NSArray仗阅、NSDictionary的比較方法‘;它們不是比較指針国夜,而是比較對(duì)象除指針之外的减噪。

- (BOOL)isEqualToString:(NSString *)aString;
- (BOOL)isEqualToArray:(NSArray<ObjectType> *)otherArray;
- (BOOL)isEqualToDictionary:(NSDictionary<KeyType, ObjectType> *)otherDictionary;
...

就拿isEqualToArray:來(lái)說(shuō)

    NSArray *array1 = @[@1];
    NSArray *array2 = @[@1];
    NSLog(@"array1: %p", &array1);
    NSLog(@"array2: %p", &array2);
    NSLog(@"result: %d", [array1 isEqualToArray:array2]);

結(jié)果:

array1: 0x7ffee26978f0
array2: 0x7ffee26978e8
result: 1

說(shuō)明array1array2是兩個(gè)不同的對(duì)象(指針不同),卻是兩個(gè)等同的對(duì)象车吹。

2筹裕、如何判斷兩個(gè)對(duì)象是否等同

NSObject協(xié)議中有兩個(gè)用于判斷等同性的方法:

- (BOOL)isEqual:(id)object;
- (NSInteger)hash;

NSObject類(lèi)對(duì)這兩個(gè)方法的默認(rèn)實(shí)現(xiàn)是:當(dāng)且僅當(dāng)對(duì)象的“指針值”完全相等的時(shí)候,這兩個(gè)對(duì)象才相等窄驹。
這就會(huì)出現(xiàn)一個(gè)問(wèn)題:如果我們希望一個(gè)NSSet中不存在等同的對(duì)象朝卒,而默認(rèn)的isEqualhash方法只會(huì)根據(jù)指針來(lái)判斷,依然會(huì)把指針不同的等同對(duì)象放入Set中乐埠,顯然抗斤,這無(wú)法做到我們想要的效果。所以現(xiàn)在我們要重寫(xiě)這兩個(gè)方法丈咐。

1. 創(chuàng)建對(duì)象People豪治,包含name和age屬性
//People.h
@interface People : NSObject

//name
@property (nonatomic, strong)NSString *name;
//age
@property (nonatomic, assign)NSInteger age;
@end
2. 模仿isEqualToArray:方法,創(chuàng)建isEqualToPeople:方法
- (BOOL)isEqualToPeople:(People *)people {
    if (self == people) return YES;  //如果指針相同扯罐,肯定是同一個(gè)對(duì)象
    if (![self.name isEqualToString:people.name]) return NO;
    if (self.age != people.age) return NO;  //如果對(duì)象的屬性不同负拟,肯定不等同
    return YES; //如果上面的條件都通過(guò)了,則是等同的對(duì)象
}

同時(shí)重寫(xiě)isEqual:方法

- (BOOL)isEqual:(id)object {
    if ([object class] == [self class]) {
        return [self isEqualToPeople:object];
    }else {
        return [super isEqual:object];
    }
}
3. 重寫(xiě)hash方法

什么是哈希碼歹河?
哈希碼并不是完全唯一的掩浙,它是一種算法,讓同一個(gè)類(lèi)的對(duì)象按照自己不同的特征盡量的有不同的哈希碼秸歧,但不表示不同的對(duì)象哈希碼完全不同厨姚。也有相同的情況,看程序員如何寫(xiě)哈希碼的算法键菱。

根據(jù)等同性約定:
若兩個(gè)對(duì)象等同谬墙,則起哈希碼也相等,但是兩個(gè)哈希嗎相同的對(duì)象卻不一定相等经备。

所以拭抬,相等的對(duì)象双霍,必須有相等的哈希碼傲须,要盡量讓不同對(duì)象的哈希碼不會(huì)重復(fù);
我們可以根據(jù)對(duì)象的屬性值哮塞,生成哈希碼纷闺;但是這樣生成的哈希碼依然會(huì)有重復(fù)的可能算凿,但是并不會(huì)有太大的影響份蝴。

- (NSUInteger)hash {
    NSInteger nameHash = [_name hash];
    NSInteger ageHash = _age;
    NSLog(@"hash: %ld", nameHash ^ ageHash);
    return nameHash ^ ageHash;
}

我們知道,isEqual:方法或者isEqualToPeople:方法是會(huì)被程序員主動(dòng)調(diào)用以判斷對(duì)象是否等同氓轰,但是hash方法就沒(méi)有isEqual方法的存在感那么強(qiáng)了婚夫。

3、何時(shí)會(huì)調(diào)用hash方法

這個(gè)問(wèn)題可以被解釋成這樣:
何時(shí)需要調(diào)用對(duì)象的哈希碼署鸡,作為或者生成一個(gè)識(shí)別碼案糙,用以識(shí)別不同的對(duì)象。
我們知道储玫,字典是根據(jù)key來(lái)尋值的,所以一個(gè)字典里不能有相同的key萤皂。
1撒穷、當(dāng)對(duì)象作為字典的key值時(shí),會(huì)調(diào)用hash方法裆熙,幫助對(duì)象稱(chēng)為字典中獨(dú)一無(wú)二的key

    People *p2 = [People new];
    p2.name = @"p2";
    p2.age = 20;
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    [dic setObject:@"Object" forKey:p2];

注意實(shí)現(xiàn)對(duì)象的copyWithZone方法

2端礼、NSSet是不允許有重復(fù)的對(duì)象的,所以向NSMutableSet中添加對(duì)象時(shí)入录,會(huì)調(diào)用對(duì)象的hash方法蛤奥,用以比較該對(duì)象是否已存在于集合中。

    People *p1 = [People new];
    p1.name = @"p1";
    p1.age = 12;
    NSMutableSet *set = [NSMutableSet set];
    [set addObject:p1];

需要注意的是:把可變對(duì)象加入到集合set中后僚稿,盡量不要改變其哈希碼了
原因:

加入集合時(shí)凡桥,新加入對(duì)象的哈希碼和集合中已存在的對(duì)象的哈希碼是不同的,如果在對(duì)象加入集合之后更改對(duì)象的哈希碼蚀同,以至于對(duì)象的哈希碼和集合中的某一個(gè)對(duì)象的哈希碼相同缅刽,那就會(huì)出現(xiàn)一些問(wèn)題。
例如:

    People *p3 = [People new];
    p3.name = @"Jack";
    p3.age = 20;

    People *p4 = [People new];
    p4.name = @"Koko";
    p4.age = 20;

    NSMutableSet *set4 = [NSMutableSet set];
    [set4 addObject:p3];
    [set4 addObject:p4];

我們上面定義了hash方法的實(shí)現(xiàn)蠢络,hash碼是根據(jù)People對(duì)象的name和age來(lái)設(shè)定的衰猛,所以p3和p4是可以加入到集合set4中的。
現(xiàn)在刹孔,我們來(lái)更改一下p4啡省,使p4和p3的哈希碼相同,看看會(huì)發(fā)送什么髓霞?

p4.name = @"Jack";

此時(shí)卦睹,p3和p4是等同的

set中出現(xiàn)兩個(gè)等同的對(duì)象.png

我們看到方库,不能存在重復(fù)對(duì)象的Set中居然存在了兩個(gè)等同的對(duì)象分预!

那么我們?nèi)绾伟堰@兩個(gè)等同的對(duì)象,去掉一個(gè)呢薪捍?

NSSet *set5 = [set4 copy];

結(jié)果:


去掉一個(gè)對(duì)象.png

通過(guò)copy方法笼痹,深拷貝了一個(gè)全新的集合配喳,這個(gè)新集合就像逐個(gè)向新集合中添加對(duì)象而創(chuàng)建出來(lái)的。這個(gè)問(wèn)題還是根據(jù)開(kāi)發(fā)者當(dāng)前的需求從而決定是否需要對(duì)set進(jìn)行去重操作凳干。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末晴裹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子救赐,更是在濱河造成了極大的恐慌涧团,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件经磅,死亡現(xiàn)場(chǎng)離奇詭異泌绣,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)预厌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)阿迈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人轧叽,你說(shuō)我怎么就攤上這事苗沧。” “怎么了炭晒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵待逞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我网严,道長(zhǎng)识樱,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任震束,我火速辦了婚禮牺荠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘驴一。我一直安慰自己休雌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布肝断。 她就那樣靜靜地躺著杈曲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胸懈。 梳的紋絲不亂的頭發(fā)上担扑,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音趣钱,去河邊找鬼涌献。 笑死,一個(gè)胖子當(dāng)著我的面吹牛首有,可吹牛的內(nèi)容都是我干的燕垃。 我是一名探鬼主播枢劝,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼卜壕!你這毒婦竟也來(lái)了您旁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤轴捎,失蹤者是張志新(化名)和其女友劉穎鹤盒,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體侦副,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侦锯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秦驯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尺碰。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖汇竭,靈堂內(nèi)的尸體忽然破棺而出葱蝗,到底是詐尸還是另有隱情穴张,我是刑警寧澤细燎,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站皂甘,受9級(jí)特大地震影響玻驻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜偿枕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一璧瞬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渐夸,春花似錦嗤锉、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至苫幢,卻和暖如春访诱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背韩肝。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工触菜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哀峻。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓涡相,卻偏偏與公主長(zhǎng)得像哲泊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漾峡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,090評(píng)論 1 32
  • 307攻旦、setValue:forKey和setObject:forKey的區(qū)別是什么? 答:1, setObjec...
    AlanGe閱讀 1,532評(píng)論 0 1
  • 孤月淚(原創(chuàng)) □ 文/小草心語(yǔ)(云南) 一半掛天上生逸,閱 人間風(fēng)情牢屋。一半埋井底 埋成,一道虛幻的景
    小草心語(yǔ)閱讀 362評(píng)論 2 11
  • 字典中對(duì)字詞的注釋會(huì)區(qū)分不同時(shí)代的不同含義槽袄,以及對(duì)應(yīng)不同語(yǔ)言的詞匯烙无,這些語(yǔ)言中該詞語(yǔ)的含義。
    弗雷辣條閱讀 98評(píng)論 0 0
  • 【標(biāo)題】賭對(duì)不變迂苛,擁抱變化。 【字?jǐn)?shù)】758 【正文】 現(xiàn)在這個(gè)社會(huì)鼓择,唯一不變的就是“變”三幻。 在我們農(nóng)村,像我們6...
    藍(lán)天_7582閱讀 134評(píng)論 0 1