iOS晉級(jí)知識(shí)匯總(二)runtime

Runtime

數(shù)據(jù)結(jié)構(gòu)

  • objc_object
  • objc_class
  • isa指針
  • method_t

objc_object id == objc_object

  • isa_t
  • 關(guān)于isa操作相關(guān)
  • 弱引用相關(guān)
  • 關(guān)聯(lián)對(duì)象相關(guān)
  • 內(nèi)存管理相關(guān)

objc_class class == objc_class 繼承于objc_object

Class superClass

cache_t cache

  • 快速查找方法執(zhí)行函數(shù)
  • 可增量擴(kuò)展的哈希表結(jié)構(gòu)
  • 局部性原理的最佳應(yīng)用
Cache_t.png

class_data_bits_t bits

- class\_data\_bits\_t主要是對(duì)class_rw_t的封裝
- class\_rw\_t代表了類相關(guān)的讀寫信息、對(duì)class\_ro\_t的封裝

class_rw_t

  • class_ro_t 代表了類相關(guān)的只讀信息
  • protocols
  • properties
  • methods
class_rw_t.png

class_ro_t

Class_ro_t.png

isa指針

  • 指針型isa 的值代表Class的地址
  • 非指針型isa 的值的部分代表Class的地址
  • 產(chǎn)生這兩種的初衷:我們?cè)趯ぶ穼?shí)際上30~40位數(shù)就可以保證我們尋找到所有class的地址,多出來的位可以存儲(chǔ)一些別的內(nèi)容,來達(dá)到節(jié)省內(nèi)存的目的
  • 指向問題:
    • 關(guān)于對(duì)象,其指向類對(duì)象
    • 關(guān)于類對(duì)象,其指向元類對(duì)象
    • 如果是實(shí)例方法從類對(duì)象查找,如果是類方法從元類對(duì)象查找
isa指針.png

method_t

method_t.png

const char * types

type Encodings技術(shù)

Type Encoding.png

數(shù)據(jù)結(jié)構(gòu)總結(jié)

Runtime數(shù)據(jù)結(jié)構(gòu).png

對(duì)象、類對(duì)象、元類對(duì)象

  • 類對(duì)象存儲(chǔ)實(shí)例方法列表等信息

  • 元類對(duì)象存儲(chǔ)類方法類表等信息

  • 類對(duì)象和元類對(duì)象都是objc_class數(shù)據(jù)結(jié)構(gòu),由于繼承了objc_object數(shù)據(jù)結(jié)構(gòu)所以才有isa指針,

  • 所以才能實(shí)例對(duì)象找到類對(duì)象訪問它的實(shí)例方法列表等信息,

  • 類對(duì)象通過isa可以找到元類對(duì)象訪問類方法列表等信息

  • 元類對(duì)象的isa指針(包含根元類對(duì)象)都指向根元類對(duì)象

  • 根元類對(duì)象的superclass指向的根類對(duì)象

    • 當(dāng)在跟類中的類方法沒找到,會(huì)指向根類對(duì)象中去查找它的同名的實(shí)例方法

消息傳遞過程

實(shí)例方法消息傳遞過程

1、 調(diào)用了一個(gè)實(shí)例對(duì)象A對(duì)象的實(shí)例方法
2、 通過A實(shí)例對(duì)象的isa指針找到它的類對(duì)象,類對(duì)象中遍歷方法列表去查找同名的方法實(shí)現(xiàn),找到后Runtime發(fā)送消息調(diào)用
3、 如果沒有找到就會(huì)根據(jù)superclass指針指向的父類對(duì)象,并查找其方法列表。。。直到根類對(duì)象中的方法列表,如果找到Runtime發(fā)送消息調(diào)用,如果到根類對(duì)象還沒有找到就會(huì)返回nil

類方的消息傳遞過程

1、 調(diào)用一個(gè)類對(duì)象的類方法。
2、 通過類對(duì)象的isa指針找到元類對(duì)象,元類對(duì)象中遍歷方法列表查找同名的類方法是心啊,找到后直接調(diào)用
3、如果沒有找到就會(huì)通過superclass指針指向父元類對(duì)象,并查找其類方法列表。。。直到根元類對(duì)象中的類方法列表,如果找到直接調(diào)用,如果沒有找到進(jìn)入到消息轉(zhuǎn)發(fā)
4、根元類對(duì)象如果沒有找到會(huì)superclass會(huì)指向根類對(duì)象,并查找同名的實(shí)例方法,如果找到直接調(diào)用,如果沒有找到返回nil

消息傳遞

消息傳遞.png
消息傳遞Supr.png
消息傳遞流程.png

1、緩存查找

例: 給定值是SEL 目標(biāo)值是對(duì)應(yīng)bucket_t的IMP。

  • 首先給定的函數(shù)選擇器通過一個(gè)函數(shù)來映射出bucket_t在數(shù)組當(dāng)中位置,這個(gè)過程是hash查找
  • 哈希查找實(shí)際上,通過給定的一個(gè)值比如說方法的選擇器經(jīng)過哈希函數(shù)的算法酸楚的值實(shí)際上就是給定值在對(duì)應(yīng)數(shù)組當(dāng)中所對(duì)應(yīng)的索引位置。
    • f(key) = key & mask
    • 通過哈希查 解決查找效率的問題
    • 通過哈希查找,找到對(duì)應(yīng)的bucket_t,就可以拿到IMP

2、當(dāng)前類中查找

對(duì)于已排序好的列表,采用二分查找算法查找方法對(duì)應(yīng)執(zhí)行函數(shù)
對(duì)于沒有排序的列表,采用一般遍歷查找方法對(duì)應(yīng)執(zhí)行函數(shù)

3、父類逐級(jí)查找

父類逐級(jí)查找的過程.png

消息轉(zhuǎn)發(fā)

消息轉(zhuǎn)發(fā).png

Method-Swizzling

MethodSwizzling.png
Method method1 = class_getInstanceMethod(self, @selector(test));
Method method2 = class_getInstanceMethod(self, @selector(Mytest));
method_exchangeImplementations(method1, method2);

動(dòng)態(tài)添加方法

編譯的時(shí)候沒有這個(gè)方法,運(yùn)行時(shí)有這個(gè)方法需要調(diào)用performSelector方法,在消息轉(zhuǎn)發(fā)中的第一次處理函數(shù)resolveInstanceMethod動(dòng)態(tài)添加DoThings:Num:方法

+ (BOOL)resolveInstanceMethod:(SEL)sel{

    NSLog(@"%@",NSStringFromSelector(sel));

    if(sel == @selector(DoThings:Num:)){
        class_addMethod([self class], sel, (IMP)MyMethodIMP, "v@:");
        return YES;
    }

    return  [super resolveInstanceMethod:sel];
}

void MyMethodIMP(id self,SEL _cmd,NSString * name,NSInteger num){
    
    NSLog(@"調(diào)用了消息轉(zhuǎn)發(fā)的內(nèi)容");
    NSLog(@"%@",NSStringFromSelector(_cmd));
    NSLog(@"%@",name);
    NSLog(@"%ld",(long)num);
}

動(dòng)態(tài)方法解析

@dynamic

  • 動(dòng)態(tài)運(yùn)行時(shí)語言將函數(shù)決議推遲到運(yùn)行時(shí)。
    • 當(dāng)我們把一個(gè)屬性標(biāo)示為@dynamic的時(shí)候代表著不需要編譯器在編譯時(shí),為我們生成屬性的setter跟getter方法的具體實(shí)現(xiàn),而在在具體運(yùn)行時(shí)我們調(diào)用了setter、geter方法的時(shí)候,再去添加具體的實(shí)現(xiàn)。
    • 這種功能也只有動(dòng)態(tài)運(yùn)行時(shí)特性的語言支持
  • 編譯時(shí)語言在編譯期進(jìn)行函數(shù)決議

面試題

nsobject有父類嗎?

沒有nsobject是根類

當(dāng)在跟類中的類方法沒找到,但是有同名的實(shí)例方法實(shí)現(xiàn),那么會(huì)不會(huì)崩潰?會(huì)不會(huì)產(chǎn)生實(shí)際的調(diào)用?

由于根元類對(duì)象的superclass指針指向了根類對(duì)象,去查找實(shí)例同名的實(shí)例方法,如果找到就會(huì)執(zhí)行同名的實(shí)例方法調(diào)用

下圖中打印的是什么?

筆試題1.png
 [self class]會(huì)轉(zhuǎn)化成     
 objc_msgSend(<#id  _Nullable self#>, <#SEL  _Nonnull op, ...#>)
 phone的實(shí)例對(duì)象,[self class],通過isa找到phone類對(duì)象,phone類對(duì)象是沒有class的,通過superclass找到父類的。。。直到查找到根類nsobject,有calss的實(shí)現(xiàn),打印出來的自然是phone
 
 [super class]會(huì)轉(zhuǎn)化成
 objc_msgSendSuper(<#struct objc_super * _Nonnull super#>, <#SEL  _Nonnull op, ...#>)
 
 objc_msgSendSuper實(shí)際的接收者仍然是phone的這個(gè)實(shí)例對(duì)象,objc_msgSendSuper傳遞的含義,從phone的這個(gè)實(shí)例對(duì)象的父類開始查找,  直到查找到根類nsobject有class的實(shí)現(xiàn),所以打印出來的結(jié)果還是phone
 

打印結(jié)果都是phone

對(duì)頁面的進(jìn)出添加進(jìn)出信息

使用MethodSwizzling來交換viewDidLoadviewWillAppear,在替換代碼中添加一些埋點(diǎn)操作

[obj foo]和objc_msgSend()函數(shù)之間有什么關(guān)系?

  • 向 obj對(duì)象發(fā)送一條foo的消息,[obj foo]在編譯期處理以后就變成了objc_msgSend(obj,@selector(foo))
  • 由于沒有參數(shù),所以 objc_msgSend函數(shù)調(diào)用只有2個(gè)參數(shù)
  • 然后就開始了runtime的消息傳遞過程

runtime如何通過Selector找到對(duì)應(yīng)的IMP地址的?

  • 查找當(dāng)前實(shí)例所對(duì)應(yīng)類對(duì)象的緩存,是否有selelctor對(duì)應(yīng)imp實(shí)現(xiàn)如果緩存命中了,
    我們就把命中的緩存函數(shù)返回給調(diào)用方。
  • 如果緩存沒有就去當(dāng)前類的方法列表查找selector對(duì)應(yīng)的imp實(shí)現(xiàn)
  • 當(dāng)前類如果沒有命中,就根據(jù)當(dāng)前類的superclass逐級(jí)查找父類的方法列表。。。直到根類對(duì)象,直到查到selector方法的imp實(shí)現(xiàn)

能否向編譯后的類中增加實(shí)例變量?

class_ro_t ro代表的是readonly

編譯后的類是無法添加實(shí)例變量的。

能否向動(dòng)態(tài)添加的類中增加實(shí)例變量?

可以的,動(dòng)態(tài)添加的這個(gè)類過程當(dāng)中只要在它調(diào)用注冊(cè)方法之前去完成實(shí)例變量的添加就是可以實(shí)現(xiàn)的

消息傳遞機(jī)制

當(dāng)我們?cè)谙鬟f的過程中如何通過緩存的方法查找?

isa指針的含義?

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

相關(guān)閱讀更多精彩內(nèi)容

  • 分類 用分類干了什么事情? 聲明私有方法 分解體積龐大類文件 把Framework的私有方法公開 特點(diǎn) 運(yùn)行時(shí)決議...
    struggle3g閱讀 105評(píng)論 0 0
  • 1.網(wǎng)絡(luò) 1.網(wǎng)絡(luò)七層協(xié)議有哪些? 物理層:主要功能:傳輸比特流;典型設(shè)備:集線器、中繼器;典型協(xié)議標(biāo)準(zhǔn)和應(yīng)用:V...
    _我和你一樣閱讀 3,863評(píng)論 1 38
  • 1.說說OC的消息機(jī)制? OC中的方法調(diào)用其實(shí)都是轉(zhuǎn)成了objc_msgSend函數(shù)的調(diào)用,給receiver(方...
    齊玉婷閱讀 548評(píng)論 0 0
  • Apple相關(guān)源碼地址 在 https://opensource.apple.com/source/[https:...
    Jason1226閱讀 444評(píng)論 0 1
  • 1.weak和assign區(qū)別 修飾變量類型的區(qū)別: weak 只可以修飾對(duì)象。如果修飾基本數(shù)據(jù)類型,編譯器會(huì)報(bào)錯(cuò)...
    coderjon閱讀 1,112評(píng)論 0 1

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