Category解析

一当悔、objc 對象的 isa 的指針指向什么?有什么作用踢代?

指向他的類對象,從而可以找到對象上的方法

詳解:下圖很好的描述了對象盲憎,類,元類之間的關(guān)系:

[圖片上傳失敗...(image-f3fe67-1661948616530)]

<figcaption>圖中實(shí)線是 super_class 指針胳挎,虛線是 isa 指針饼疙。</figcaption>

1.Root class (class)其實(shí)就是 NSObject,NSObject 是沒有超類的慕爬,所以 Root class(class)的 superclass

指向 nil窑眯。

2.每個 Class 都有一個 isa 指針指向唯一的 Meta class

3.Root class(meta)的 superclass 指向 Root class(class),也就是 NSObject医窿,形成一個回路伸但。

4.每個 Meta class 的 isa 指針都指向 Root class (meta)。

二留搔、一個 NSObject 對象占用多少內(nèi)存空間更胖?

受限于內(nèi)存分配的機(jī)制,一個 NSObject 對象都會分配 16byte 的內(nèi)存空間。

但是實(shí)際上在 64 位 下却妨,只使用了 8byte;

在 32 位下饵逐,只使用了 4byte

一個 NSObject 實(shí)例對象成員變量所占的大小,實(shí)際上是 8 字節(jié)

[圖片上傳失敗...(image-9f6aec-1661948616530)]

本質(zhì)是

[圖片上傳失敗...(image-708660-1661948616530)]

獲取Obj-C指針?biāo)赶虻膬?nèi)存的大小彪标,實(shí)際上是

[圖片上傳失敗...(image-a7dcb3-1661948616529)]

對象在分配內(nèi)存空間時倍权,會進(jìn)行內(nèi)存對齊,所以在iOS中捞烟,分配內(nèi)存空間都是16字節(jié)的倍數(shù)薄声。

可以通過以下網(wǎng)址:http://openSource.apple.com/tarballs來查看源代碼。

三题画、說一下對class_rw_t的理解默辨?

rw代表可讀可寫。ObjC類中的屬性苍息、方法還有遵循的協(xié)議等信息都保存在class_rw_t中:

[圖片上傳失敗...(image-70997f-1661948616529)]

四缩幸、說一下對class_ro_t的理解?

存儲了當(dāng)前類在編譯期就已經(jīng)確定的屬性竞思、方法以及遵循的協(xié)議

[圖片上傳失敗...(image-939002-1661948616529)]

五表谊、、說一下對isa指針的理解盖喷,對象的isa指針指向哪里爆办?isa指針有哪兩種類型?

isa等價于 is kind of

  • 實(shí)例對象isa指向類對象
  • 類對象指isa向元類對象
  • 元類對象的isa指向元類的基類

isa有兩種類型

  • 純指針课梳,指向內(nèi)存地址
  • NON_POINTER_ISA距辆,除了內(nèi)存地址,還存有一些其他信息

isa源碼分析

在Runtime源碼查看sa_t是共用體惦界。簡化結(jié)構(gòu)如下:

[圖片上傳失敗...(image-8790ca-1661948616529)]

六挑格、說一下untime的方法緩存咙冗?存儲的形式沾歪、數(shù)據(jù)結(jié)構(gòu)以及查找的過程?

cache_t增量擴(kuò)展的哈希表結(jié)構(gòu)雾消。哈希表內(nèi)部存儲的bucket_t灾搏。

bucket_t中存儲的是SEL和IMP的鍵值對。

  • 如果是有序方法列表立润,采用二分查找
  • 如果是無序方法列表狂窑,直接遍歷查找

cache_t結(jié)構(gòu)體

[圖片上傳失敗...(image-8fa82e-1661948616529)]

七、使用 runtime Associate 方法關(guān)聯(lián)的對象桑腮,需要在主對象 dealloc 的時候釋放么泉哈?

無論在 MRC 下還是 ARC 下均不需要,被關(guān)聯(lián)的對象在生命周期內(nèi)要比對象本身釋放的晚很多,它們會在

被 NSObject -dealloc 調(diào)用的 object_dispose()方法中釋放丛晦。

[圖片上傳失敗...(image-2b761-1661948616529)]

[圖片上傳失敗...(image-418550-1661948616529)]

十奕纫、什么時候會報 unrecognized selector 的異常?

objc 在向一個對象發(fā)送消息時烫沙,runtime 庫會根據(jù)對象的 isa 指針找到該對象實(shí)際所屬的類匹层,然后在該類中

的方法列表以及其父類方法列表中尋找方法運(yùn)行,如果锌蓄,在最頂層的父類中依然找不到相應(yīng)的方法時升筏,會

進(jìn)入消息轉(zhuǎn)發(fā)階段,如果消息三次轉(zhuǎn)發(fā)流程仍未實(shí)現(xiàn)瘸爽,則程序在運(yùn)行時會掛掉并拋出異常 unrecognized

selector sent to XXX 您访。

十一、如何給 Category 添加屬性蝶糯?關(guān)聯(lián)對象以什么形式進(jìn)行存儲洋只?

查看的是 關(guān)聯(lián)對象 的知識點(diǎn)。

詳細(xì)的說一下 關(guān)聯(lián)對象昼捍。

關(guān)聯(lián)對象 以哈希表的格式识虚,存儲在一個全局的單例中。

[圖片上傳失敗...(image-8d07a4-1661948616529)]

十二妒茬、能否向編譯后得到的類中增加實(shí)例變量担锤?能否向運(yùn)行時創(chuàng)建的類中添加實(shí)例變量?

為什么乍钻?

不能向編譯后得到的類中增加實(shí)例變量肛循;

能向運(yùn)行時創(chuàng)建的類中添加實(shí)例變量;

1.因?yàn)榫幾g后的類已經(jīng)注冊在 runtime 中,類結(jié)構(gòu)體中的 objc_ivar_list 實(shí)例變量的鏈表和 instance_size

實(shí)例變量的內(nèi)存大小已經(jīng)確定银择,同時 runtime 會調(diào)用 class_setvarlayout 或 class_setWeaklvarLayout 來

處理 strong weak 引用.所以不能向存在的類中添加實(shí)例變量多糠。

2.運(yùn)行時創(chuàng)建的類是可以添加實(shí)例變量,調(diào)用 class_addIvar 函數(shù). 但是的在調(diào)用 objc_allocateClassPair

之后浩考,objc_registerClassPair 之前,原因同上.

[圖片上傳失敗...(image-d0c96d-1661948616529)]

十四夹孔、runtime 如何通過 selector 找到對應(yīng)的 IMP 地址?

每一個類對象中都一個方法列表,方法列表中記錄著方法的名稱,方法實(shí)現(xiàn),以及參數(shù)類型,其實(shí) selector 本質(zhì)就是方法名稱,通過這個方法名稱就可以在方法列表中找到對應(yīng)的方法實(shí)現(xiàn).析孽、

十五搭伤、runtime 如何實(shí)現(xiàn) weak 變量的自動置 nil?知道 SideTable 嗎袜瞬?

runtime 對注冊的類會進(jìn)行布局怜俐,對于 weak 修飾的對象會放入一個 hash 表中。 用 weak 指向的對象內(nèi) 存地址作為 key邓尤,當(dāng)此對象的引用計(jì)數(shù)為 0 的時候會 dealloc拍鲤,假如 weak 指向的對象內(nèi)存地址是 a贴谎,那么就 會以 a 為鍵, 在這個 weak 表中搜索季稳,找到所有以 a 為鍵的 weak 對象赴精,從而設(shè)置為 nil。

更細(xì)一點(diǎn)的回答:

1.初始化時:runtime 會調(diào)用 objc_initWeak 函數(shù)绞幌,初始化一個新的 weak 指針指向?qū)ο蟮牡刂贰?/p>

2.添加引用時:objc_initWeak 函數(shù)會調(diào)用 objc_storeWeak() 函數(shù)蕾哟, objc_storeWeak()的作用是更新指針指向,創(chuàng)建對應(yīng)的弱引用表莲蜘。

3.釋放時,調(diào)用 clearDeallocating 函數(shù)谭确。clearDeallocating 函數(shù)首先根據(jù)對象地址獲取所有 weak 指針地址的數(shù)組,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為 nil票渠,最后把這個 entry 從 weak 表中刪除逐哈,最后清理對象的記錄。

SideTable 結(jié)構(gòu)體是負(fù)責(zé)管理類的引用計(jì)數(shù)表和 weak 表问顷,

詳解:參考自《Objective-C 高級編程》一書

[圖片上傳失敗...(image-80e7a0-1661948616529)]

[圖片上傳失敗...(image-232c49-1661948616529)]

3. 釋放時,調(diào)用 clearDeallocating 函數(shù)昂秃。clearDeallocating 函數(shù)首先根據(jù)對象地址獲取所有 weak 指針地址的數(shù)組,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為 nil杜窄,最后把這個 entry 從 weak 表中刪除肠骆,最后清理對象的記錄。

當(dāng) weak 引用指向的對象被釋放時塞耕,又是如何去處理 weak 指針的呢蚀腿?當(dāng)釋放對象時,其基本流程如下:

1.調(diào)用 objc_release

2.因?yàn)閷ο蟮囊糜?jì)數(shù)為 0扫外,所以執(zhí)行 dealloc

3.在 dealloc 中莉钙,調(diào)用了_objc_rootDealloc 函數(shù)

4.在_objc_rootDealloc 中,調(diào)用了 object_dispose 函數(shù)

5.調(diào)用 objc_destructInstance

6.最后調(diào)用 objc_clear_deallocating

對象被釋放時調(diào)用的 objc_clear_deallocating 函數(shù):

1.從 weak 表中獲取廢棄對象的地址為鍵值的記錄

2.將包含在記錄中的所有附有 weak 修飾符變量的地址筛谚,賦值為 nil3.將 weak 表中該記錄刪除

4.從引用計(jì)數(shù)表中刪除廢棄對象的地址為鍵值的記錄

總結(jié):

其實(shí) Weak 表是一個 hash(哈希)表磁玉,Key 是 weak 所指對象的地址,Value 是 weak 指針的地址(這個地址的值是所指對象指針的地址)數(shù)組驾讲。

十六蚊伞、objc 中向一個 nil 對象發(fā)送消息將會發(fā)生什么?

如果向一個 nil 對象發(fā)送消息蝎毡,首先在尋找對象的 isa 指針時就是 0 地址返回了厚柳,所以不會出現(xiàn)任何錯誤氧枣。 也不會崩潰沐兵。

詳解:

如果一個方法返回值是一個對象,那么發(fā)送給 nil 的消息將返回 0(nil)便监;

如果方法返回值為指針類型扎谎,其指針大小為小于或者等于 sizeof(void*) 碳想,float,double毁靶,long double 或

者 long long 的整型標(biāo)量胧奔,發(fā)送給 nil 的消息將返回 0;

如果方法返回值為結(jié)構(gòu)體,發(fā)送給 nil 的消息將返回 0预吆。結(jié)構(gòu)體中各個字段的值將都是 0龙填;

如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給 nil 的消息的返回值將是未定義的拐叉。

十七岩遗、objc 在向一個對象發(fā)送消息時,發(fā)生了什么凤瘦?

objc 在向一個對象發(fā)送消息時宿礁,runtime 會根據(jù)對象的 isa 指針找到該對象實(shí)際所屬的類,然后在該類中的 方法列表以及其父類方法列表中尋找方法運(yùn)行蔬芥,如果一直到根類還沒找到梆靖,轉(zhuǎn)向攔截調(diào)用,走消息轉(zhuǎn)發(fā)機(jī)制笔诵,一旦找到 返吻,就去執(zhí)行它的實(shí)現(xiàn) IMP 。

[圖片上傳失敗...(image-94ab67-1661948616529)]

詳解:

在 isKindOfClass 中有一個循環(huán)乎婿,先判斷 class 是否等于 meta class思喊,不等就繼續(xù)循環(huán)判斷是否等于 meta class 的 super class,不等再繼續(xù)取 super class次酌,如此循環(huán)下去恨课。

[NSObject class]執(zhí)行完之后調(diào)用 isKindOfClass,第一次判斷先判斷 NSObject 和 NSObject 的 meta class 是否相等岳服,之前講到 meta class 的時候放了一張很詳細(xì)的圖剂公,從圖上我們也可以看出,NSObject 的 meta class 與本身不等吊宋。接著第二次循環(huán)判斷 NSObject 與 meta class 的 superclass 是否相等纲辽。還是從那張圖 上面我們可以看到:Root class(meta) 的 superclass 就是 Root

class(class),也就是 NSObject 本身璃搜。所以第二次循環(huán)相等拖吼,于是第一行 res1 輸出應(yīng)該為 YES。

同理这吻,[Sark class]執(zhí)行完之后調(diào)用 isKindOfClass吊档,第一次 for 循環(huán),Sark 的 Meta Class 與[Sark class] 不等唾糯,第二次 for 循環(huán)怠硼,Sark Meta Class 的 super class 指向的是 NSObject Meta Class鬼贱, 和 Sark Class不相等。第三次 for 循環(huán)香璃,NSObject Meta Class 的 super class 指向的是 NSObject Class这难,和 Sark Class 不相等。第四次循環(huán)葡秒,NSObject Class 的 super class 指向 nil姻乓, 和 Sark Class 不相等。第四次循環(huán)之 后眯牧,退出循環(huán)糖权,所以第三行的 res3 輸出為 NO。

isMemberOfClass 的源碼實(shí)現(xiàn)是拿到自己的 isa 指針和自己比較炸站,是否相等星澳。

第二行 isa 指向 NSObject 的 Meta Class,所以和 NSObject Class 不相等旱易。第四行禁偎,isa 指向 Sark 的Meta Class,和 Sark Class 也不等阀坏,所以第二行 res2 和第四行 res4 都輸出 NO如暖。

十九、Category 在編譯過后忌堂,是在什么時機(jī)與原有的類合并到一起的盒至?

1. 程序啟動后,通過編譯之后士修,Runtime 會進(jìn)行初始化枷遂,調(diào)用 _objc_init。

2. 然后會 map_images棋嘲。

3. 接下來調(diào)用 map_images_nolock酒唉。

4. 再然后就是 read_images,這個方法會讀取所有的類的相關(guān)信息沸移。

5. 最后是調(diào)用 reMethodizeClass:痪伦,這個方法是重新方法化的意思。

6. 在 reMethodizeClass: 方法內(nèi)部會調(diào)用 attachCategories: 雹锣,這個方法會傳入 Class 和 Category 网沾,會將方法列表,協(xié)議列表等與原有的類合并蕊爵。最后加入到 class_rw_t 結(jié)構(gòu)體中辉哥。

二十、Category 有哪些用途在辆?

? 給系統(tǒng)類添加方法证薇、屬性(需要關(guān)聯(lián)對象)。

?對某個類大量的方法匆篓,可以實(shí)現(xiàn)按照不同的名稱歸類浑度。

二十一、Category 的實(shí)現(xiàn)原理鸦概?

被添加在了 class_rw_t 的對應(yīng)結(jié)構(gòu)里箩张。

Category 實(shí)際上是 Category_t 的結(jié)構(gòu)體,在運(yùn)行時窗市,新添加的方法先慷,都被以倒序插入到原有方法列 表的最前面,所以不同的 Category咨察,添加了同一個方法论熙,執(zhí)行的實(shí)際上是最后一個。

拿方法列表舉例摄狱,實(shí)際上是一個二維的數(shù)組脓诡。

Category 如果翻看源碼的話就會知道實(shí)際上是一個 _catrgory_t 的結(jié)構(gòu)體。

--

例如我們在程序中寫了一個 Nsobject+Tools 的分類媒役,那么被編譯為 C++ 之后祝谚,實(shí)際上是:

[圖片上傳失敗...(image-eb2544-1661948616529)]

二十二、_objc_msgForward 函數(shù)是做什么的酣衷,直接調(diào)用它將會發(fā)生什么交惯?

_objc_msgForward 是 IMP 類型,用于消息轉(zhuǎn)發(fā)的:當(dāng)向一個對象發(fā)送一條消息穿仪,但它并沒有實(shí)現(xiàn)的時候席爽, _objc_msgForward 會嘗試做消息轉(zhuǎn)發(fā)。

詳解:_objc_msgForward 在進(jìn)行消息轉(zhuǎn)發(fā)的過程中會涉及以下這幾個方法:

1. List itemresolveInstanceMethod:方法 (或 resolveClassMethod:)啊片。

2. List itemforwardingTargetForSelector:方法

3. List itemmethodSignatureForSelector:方法

4. List itemforwardInvocation:方法

5. List itemdoesNotRecognizeSelector: 方法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拳昌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子钠龙,更是在濱河造成了極大的恐慌炬藤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碴里,死亡現(xiàn)場離奇詭異沈矿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)咬腋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門羹膳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人根竿,你說我怎么就攤上這事陵像【椭椋” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵醒颖,是天一觀的道長妻怎。 經(jīng)常有香客問我,道長泞歉,這世上最難降的妖魔是什么逼侦? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮腰耙,結(jié)果婚禮上榛丢,老公的妹妹穿的比我還像新娘。我一直安慰自己挺庞,他們只是感情好晰赞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著选侨,像睡著了一般宾肺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上侵俗,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天锨用,我揣著相機(jī)與錄音,去河邊找鬼隘谣。 笑死增拥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的寻歧。 我是一名探鬼主播掌栅,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼码泛!你這毒婦竟也來了猾封?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤噪珊,失蹤者是張志新(化名)和其女友劉穎晌缘,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痢站,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡磷箕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了阵难。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岳枷。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出空繁,到底是詐尸還是另有隱情殿衰,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布盛泡,位于F島的核電站闷祥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏饭于。R本人自食惡果不足惜蜀踏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一维蒙、第九天 我趴在偏房一處隱蔽的房頂上張望掰吕。 院中可真熱鬧,春花似錦颅痊、人聲如沸殖熟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽菱属。三九已至,卻和暖如春舰罚,著一層夾襖步出監(jiān)牢的瞬間纽门,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工营罢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赏陵,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓饲漾,卻偏偏與公主長得像蝙搔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子考传,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354

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