一当悔、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: 方法