iOS底層系列:關(guān)聯(lián)對象

前言

之前我們聊過了,在Category中聲明一個屬性,可以自己手動實現(xiàn)set和get方法,但是因為沒有成員變量拴袭,所以說并不能儲值。

我們可以通過runtime的api實現(xiàn)讓成員變量可以儲值曙博,其實本質(zhì)也并不是儲存拥刻,而是通過關(guān)聯(lián)對象實現(xiàn)了這種看似是可以儲值的效果。

我們可以用下面的方法來設(shè)置關(guān)聯(lián)對象父泳。

objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)

objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key);

今天我們就來探究一下這種關(guān)聯(lián)對象的實現(xiàn)邏輯般哼。

實現(xiàn)

我們在runtime源碼中搜索objc_setAssociatedObject吴汪,最終可以定位到下面這個方法。

_object_set_associative_reference

通過簡單的分析源碼蒸眠,我們可以看出關(guān)聯(lián)對象的實現(xiàn)漾橙,大致是由下面四個類結(jié)合實現(xiàn)的。

AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation

簡單的抽取和簡化一下源碼楞卡,基本可以得出這四個類的關(guān)系霜运。

class AssociationsManager {
    static AssociationsHashMap * _map
}

typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMap;

typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap;

class ObjcAssociation {
    uintptr_t _policy;
    id _value;
};

大家也可以看一下下面這幅圖。

association_1.png

這里很清晰的表明了這幾個類的關(guān)系臀晃,AssociationsManager有一個AssociationsHashMap類型的屬性_map觉渴,_map的key是DisguisedPtr<objc_object>類型,value是ObjectAssociationMap類型徽惋,而這個ObjectAssociationMap類型中的key是一個指針(void*),value是ObjcAssociation類型座韵。這個ObjcAssociation中有兩個重要的是就是屬性险绘,_policy和_value。

關(guān)聯(lián)對象的設(shè)置就是通過這幾個類來實現(xiàn)的誉碴,上面我們也分析完了這幾個類的相互關(guān)系宦棺,那這些類和我們在調(diào)用objc_setAssociatedObject時傳入的參數(shù)關(guān)系是怎么樣的呢?我們繼續(xù)分析源碼黔帕。

我們在看一遍下面這方法代咸。

objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)

在調(diào)用的時候我們傳入了四個參數(shù),第一個就是我們的被關(guān)聯(lián)對象成黄,第二個是我們設(shè)置的關(guān)聯(lián)對象的key呐芥, 第三個就是我們要存的值,第四個就是關(guān)聯(lián)的策略(類似retain奋岁,copy等)

這里先直接說結(jié)果吧思瘟,其實可以理解為AssociationsManager的屬性_map中,以參數(shù)object為key闻伶,value是一個ObjectAssociationMap類型的map滨攻。ObjectAssociationMap中,則是以參數(shù)中的key為key蓝翰,value是一個ObjcAssociation類型的對象光绕,最后我們參數(shù)中的value和policy就儲存在這個ObjectAssociation變量中。

好了畜份,這樣我們傳的四個參就跟這些類對應(yīng)上了诞帐。就像下圖這樣子。

association_2.png

注意:

通過源碼我們知道漂坏,AssociationsHashMap中的key并不是使用直接使用了object景埃,而是一個DisguisedPtr類型媒至,但是通過源碼我們可以看到DisguisedPtr<objc_object> disguised{(objc_object *)object};,說到底這個key也是根據(jù)我們的object來生成的谷徙,所以可以說這個key與我們的object是對應(yīng)關(guān)系拒啰,從而可以理解為是這個object為key。

不得不說完慧,蘋果的設(shè)計還是很巧妙的谋旦,每一個要設(shè)置關(guān)聯(lián)對象的對象對應(yīng)一個map,在這個map中屈尼,使用我們自己設(shè)置的不同的關(guān)聯(lián)對象的key為key册着,用關(guān)聯(lián)對象的value和策略生成一個ObjcAssociation類型的對象為value,然后進(jìn)行儲存脾歧,這樣每一個要設(shè)置關(guān)聯(lián)對象的對象甲捏,具體的每一個關(guān)聯(lián)對象,都能一一對應(yīng)起來了鞭执。

上面的話說的有點拗口司顿,相信大家可以理解。

總結(jié)和補(bǔ)充

關(guān)聯(lián)對象并不是儲存在被關(guān)聯(lián)對象本身的兄纺,而是儲存在全局的統(tǒng)一的一個AssociationsHashMap中大溜。

從源碼中我們還可以看出如果我們給關(guān)聯(lián)對象設(shè)置nil,則代表移除該關(guān)聯(lián)對象估脆。

同時還要注意钦奋,因為我們的object其實是一個對象,這就要涉及內(nèi)存管理問題疙赠,當(dāng)我們的這個object釋放后付材,其實整個AssociationsHashMap中其對應(yīng)項都會被移除,這個以后我們討論內(nèi)存管理的時候再說棺聊。

objc_getAssociatedObject實現(xiàn)咱們就不具體分析了伞租,如果看動了set的實現(xiàn),get其實很容易理解限佩。

感謝閱讀葵诈。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市祟同,隨后出現(xiàn)的幾起案子作喘,更是在濱河造成了極大的恐慌,老刑警劉巖晕城,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泞坦,死亡現(xiàn)場離奇詭異,居然都是意外死亡砖顷,警方通過查閱死者的電腦和手機(jī)贰锁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門赃梧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人豌熄,你說我怎么就攤上這事授嘀。” “怎么了锣险?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵蹄皱,是天一觀的道長。 經(jīng)常有香客問我芯肤,道長巷折,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任崖咨,我火速辦了婚禮锻拘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘掩幢。我一直安慰自己逊拍,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布际邻。 她就那樣靜靜地躺著,像睡著了一般芍阎。 火紅的嫁衣襯著肌膚如雪世曾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天谴咸,我揣著相機(jī)與錄音轮听,去河邊找鬼。 笑死岭佳,一個胖子當(dāng)著我的面吹牛血巍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播珊随,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼述寡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了叶洞?” 一聲冷哼從身側(cè)響起鲫凶,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衩辟,沒想到半個月后螟炫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡艺晴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年昼钻,在試婚紗的時候發(fā)現(xiàn)自己被綠了掸屡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡然评,死狀恐怖仅财,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沾瓦,我是刑警寧澤满着,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贯莺,受9級特大地震影響风喇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缕探,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一魂莫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爹耗,春花似錦耙考、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至山卦,卻和暖如春鞋邑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背账蓉。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工枚碗, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人铸本。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓肮雨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親箱玷。 傳聞我的和親對象是個殘疾皇子怨规,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355