iOS關(guān)聯(lián)對象的底層實現(xiàn)

分類不能直接添加成員變量,可以通過關(guān)聯(lián)對象間接達(dá)到添加成員變量的效果,不能添加成員變量是由于分類的底層結(jié)構(gòu)體是這樣的

分類里面有實例方法列表、類方法列表、協(xié)議列表、實例屬性列表、類屬性列表,沒有成員變量列表,類似ivars的變量,所以分類中不能添加成員變量,下面通過代碼看下

上圖可以看出,給類WPPerson添加了一個分類,然后定義了一個name屬性,在getter方法中使用_name成員變量是報錯的

其實也可以手動實現(xiàn)有成員變量的假象,讓外部使用起來沒有什么感覺,做法是定義一個全局字典,將外部調(diào)用setter方法傳進(jìn)來的數(shù)據(jù)保存在字典中,大家可以自己嘗試下。

下面說下關(guān)聯(lián)對象的使用,關(guān)聯(lián)對象主要是通過調(diào)用兩個方法來實現(xiàn)


先說下這幾個參數(shù):

參數(shù)1:需要關(guān)聯(lián)的對象,傳self

參數(shù)2:key,這是一個void*,所以傳一個地址進(jìn)去

參數(shù)3:value,外部傳入的值

參數(shù)4:關(guān)聯(lián)存儲策略,和我們平時修飾屬性時一樣,copy,strong,assign,nonatomic。。。

用法很簡單,由于在分類中添加屬性,系統(tǒng)只會生成該屬性的setter和getter方法的申明,所以需要自己寫實現(xiàn)


這樣外部在使用時和在類里面定義的屬性就沒有什么區(qū)別,但底層實現(xiàn)和直接在類里面定義的屬性是不一樣的,下面通過源碼看下關(guān)聯(lián)對象的底層實現(xiàn)

主要實現(xiàn)在_object_set_associative_reference方法里面,先說下這幾個類的關(guān)系

AssociationsManager結(jié)構(gòu)



AssociationsHashMap結(jié)構(gòu)



ObjectAssociationMap結(jié)構(gòu)



ObjectAssociation結(jié)構(gòu)

AssociationsManager:管理者

AssociationsHashMap:里面存儲著所有關(guān)聯(lián)對象的信息,一個鍵值就是一個關(guān)聯(lián)對象的信息(WPPerson、WPCat。。。)

AssociationsHashMap:里面存儲著當(dāng)前WPPerson關(guān)聯(lián)對象的所有關(guān)聯(lián)屬性信息,一個鍵值就是一個屬性信息(name、age。。)

ObjectAssociation:里面存儲著當(dāng)前屬性的關(guān)聯(lián)策略以及具體的值

這樣一層層的就能找到對應(yīng)的關(guān)聯(lián)信息,比如我們想獲取WPPerson的name屬性的值時,先找到AssociationsManager里面的AssociationsHashMap,再通過WPPerson的實例作為key從AssociationsHashMap找到對應(yīng)的value也就是AssociationsHashMap,再通過name的key也就是@selector(name)最為key從AssociationsHashMap中找到ObjectAssociation,這樣就能拿到name屬性的具體值了

下面給源碼添加了注釋

清除關(guān)聯(lián)對象只需要調(diào)用方法的時候?qū)alue傳入nil即可

所以關(guān)聯(lián)對象底層其實是用一個全局的hashMap將self與所謂的成員變量保存起來,并不是存在類對象或者元類對象里面

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容