OC運(yùn)行時(shí)機(jī)制Runtime(一):從isa指針開始初步結(jié)識(shí)Runtime

Runtime最全總結(jié)

本系列詳細(xì)講解Runtime知識(shí)點(diǎn),由于運(yùn)行時(shí)的內(nèi)容較多,所以將內(nèi)容拆分成以下幾個(gè)方面,可以自行選擇想要查看的部分

本文主要分析Runtime的基本特性,探究OC面向?qū)ο蟮幕緦?shí)現(xiàn)务漩。

什么是運(yùn)行時(shí)?

眾所周知Objective-C是一門動(dòng)態(tài)語言它褪,動(dòng)態(tài)語言和靜態(tài)語言的區(qū)別是動(dòng)態(tài)語言可以在運(yùn)行期決定饵骨,一些類或?qū)ο罂梢栽谶\(yùn)行期暴露出來,而不需要在編譯時(shí)決定是否有這個(gè)類或?qū)ο竺4颍呙黠@區(qū)別是居触,動(dòng)態(tài)語言取決于運(yùn)行環(huán)境,靜態(tài)語言取決于編譯器老赤,例如使用多態(tài)時(shí)轮洋,靜態(tài)語言在運(yùn)行時(shí)要根據(jù)虛方法表查出應(yīng)該是哪個(gè)函數(shù)實(shí)現(xiàn),而動(dòng)態(tài)語言無論是否多態(tài)下都會(huì)在運(yùn)行時(shí)查找要執(zhí)行的方法抬旺,在這里Runtime是實(shí)現(xiàn)這門動(dòng)態(tài)語言的基礎(chǔ)弊予,從把面向?qū)ο蟮念惥幾g為面向過程的結(jié)構(gòu)體少不了它的作用,也許我們平時(shí)工作中不是很直觀的經(jīng)常使用它开财,但是可以說如果沒有Runtime就沒有Objective-C這門語言的成功汉柒。

isa指針?责鳍?這啥玩意D牍印!

首先isa指針的全稱历葛,is a kind of 指針正塌,顧名思義我們可以先理解為指向它所在類型的指針,如果一個(gè)類創(chuàng)建了一個(gè)實(shí)例,那么可以通過這個(gè)指針指向找到所在的類乓诽,下面打開objc.h文件

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

看的出每個(gè)objc_object對(duì)象都有一個(gè)指向Class類型的isa指針帜羊,再打開runtime.h文件

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

這里有Class類型的isa指針還有super_class,也可以看出isa指針并不是指向父類指針鸠天,這個(gè)結(jié)構(gòu)體里面的內(nèi)容很直觀逮壁,isa指針、指向父類指針粮宛、名稱、版本卖宠、信息巍杈、變量大小、變量列表扛伍、方法列表等等筷畦,每個(gè)objc_object可以通過isa指針找到它的類,并找到想要實(shí)現(xiàn)的方法或遵循的協(xié)議刺洒,由于objc_class也有isa指針鳖宾,所以objc_class也是一個(gè)對(duì)象,稱為“類對(duì)象”逆航,它的isa指針指向他的元類(Meta-Class)鼎文,這樣一來就很清晰了,每個(gè)對(duì)象通過isa指針向類中查找信息因俐,類對(duì)象通過isa指針向元類查找信息拇惋,每個(gè)實(shí)例對(duì)象或類對(duì)象根據(jù)super_class指針都可以找到它們的父類,至此整個(gè)繼承傳遞結(jié)構(gòu)出來了抹剩,引用大神的圖


實(shí)例對(duì)象撑帖、類和元類的關(guān)系圖

到此為止有些朋友可能對(duì)isa和superclass這兩個(gè)指針的含義理解的不是很清晰,那么下面用一個(gè)常見的案例來分析一下

假設(shè)有Father和Son兩個(gè)類澳眷,Son繼承自Father類胡嘿,在Son.m文件中寫下以下代碼

#import "Son.h"

@implementation Son

- (instancetype)init {
    if (self = [super init]) {
        NSLog(@"%@", [self class]);
        NSLog(@"%@", [super class]);
        NSLog(@"%@", self.superclass);
    }
    return self;
}

@end

初始化Son類的實(shí)例對(duì)象,觀察一下打印結(jié)果

2019-02-25 17:07:35.386429+0800 Demo[21294:1762905] Son
2019-02-25 17:07:35.386637+0800 Demo[21294:1762905] Son
2019-02-25 17:07:35.386670+0800 Demo[21294:1762905] Father

可以看出[super class]的打印結(jié)果并不是Father钳踊,而self.superclass的輸出結(jié)果是Father衷敌。這里用Runtime的角度分析一下出現(xiàn)這個(gè)結(jié)果的原因。
首先super關(guān)鍵字并不是指self的父類對(duì)象箍土,它的作用是訪問從當(dāng)前對(duì)象或類從父類繼承過來的方法逢享,其實(shí)等同于isa指針從當(dāng)前類的方法列表中找不到class方法,需要向元類中查找吴藻,如果找不到則繼續(xù)向父類依次查找直到NSObject瞒爬,這里無論是self還是super最后都是在基類的方法中找到class這個(gè)方法,而方法的調(diào)用者(OC中指消息的接受者)都是self,所以都是Son類
superclass指針直接指向當(dāng)前類的父類侧但,所以輸出是Father矢空,這兩個(gè)方法有本質(zhì)上的區(qū)別
使用clang將Son.m文件編譯成cpp文件clang -rewrite-objc Son.m在最下面找到這段c++代碼

NSLog((NSString *)&__NSConstantStringImpl__var_folders__w_bfstkhhs0c99d31tbzcqycpm0000gp_T_Son_127820_mi_0, ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class")));
NSLog((NSString *)&__NSConstantStringImpl__var_folders__w_bfstkhhs0c99d31tbzcqycpm0000gp_T_Son_127820_mi_1, ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("class")));
NSLog((NSString *)&__NSConstantStringImpl__var_folders__w_bfstkhhs0c99d31tbzcqycpm0000gp_T_Son_127820_mi_2, ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("superclass")));

這段代碼太長了,我們只保留帶類型的關(guān)鍵部分將它簡(jiǎn)化一下

((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"))
((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("class"))
((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("superclass"))

這里有一個(gè)類型__rw_objc_super禀横,只要使用super關(guān)鍵字調(diào)用方法屁药,都會(huì)構(gòu)建這個(gè)結(jié)構(gòu)體,根據(jù)isa指針向上查找方法柏锄,將所有類型全部去掉得到最簡(jiǎn)化的代碼

(self, sel_registerName("class"))
({self,class_getSuperclass(objc_getClass("Son"))},sel_registerName("class"))
(self, sel_registerName("superclass"))

最簡(jiǎn)化代碼看得出酿箭,前兩個(gè)雖然代碼不同,但是receiver參數(shù)都是self趾娃,最后調(diào)用的方法都是class缭嫡,只是查找的來源不是同一個(gè)對(duì)象,而最后一個(gè)self接收的方法是superclass查找的是父類抬闷,這樣也就印證了上面的理論妇蛀。

這里如果消息傳遞內(nèi)容不是很清晰,請(qǐng)移步到下一篇文章OC運(yùn)行時(shí)機(jī)制Runtime(二):探索Runtime的消息轉(zhuǎn)發(fā)機(jī)制

接下來再用一個(gè)案例來確定確實(shí)有Meta-Class這個(gè)概念笤成。

NSLog(@"%@", object_getClass(self));
NSLog(@"%@", object_getClass([self class]));
NSLog(@"%d", class_isMetaClass(object_getClass(self)));
NSLog(@"%d", class_isMetaClass(object_getClass([self class])));

這兩個(gè)函數(shù)很容易看懂评架,分別是獲取當(dāng)前的類對(duì)象,以及判斷當(dāng)前類是否為元類炕泳,輸出結(jié)果如下

2019-02-28 17:05:26.138644+0800 Demo[3114:1623664] Son
2019-02-28 17:05:26.138948+0800 Demo[3114:1623664] Son
2019-02-28 17:05:26.138971+0800 Demo[3114:1623664] 0
2019-02-28 17:05:26.138987+0800 Demo[3114:1623664] 1

這下很清晰了纵诞,雖然同樣結(jié)果都是Son類,但是其中一個(gè)是類對(duì)象培遵,另一個(gè)是元類挣磨,所以可以判斷,一個(gè)實(shí)例對(duì)象的isa指針指向它的類對(duì)象荤懂,而類對(duì)象的isa指針則指向它的元類茁裙。

總結(jié)

super關(guān)鍵字不代表父類對(duì)象,而是從isa指針指向的對(duì)象节仿,而消息的接受者還是self本身晤锥。每個(gè)對(duì)象都有一個(gè)isa指針,實(shí)例對(duì)象的指針指向它的類廊宪,類對(duì)象的指針指向元類矾瘾,所有的Class對(duì)象構(gòu)成了類的繼承體系,所以箭启,每個(gè)對(duì)象所要執(zhí)行的方法都要由isa指針向上查找壕翩,實(shí)例對(duì)象的方法存在于類中,類方法存在于元類中傅寡,這樣就完整的將OC的類映射到了C的結(jié)構(gòu)體上了放妈。

后續(xù)

到這里只分析了Runtime的基本關(guān)系和指針傳遞北救,后文會(huì)繼續(xù)分析消息機(jī)制和關(guān)聯(lián)對(duì)象等知識(shí)點(diǎn),感興趣的朋友們可以移步下一篇文章 OC運(yùn)行時(shí)機(jī)制Runtime(二):探索Runtime的消息轉(zhuǎn)發(fā)機(jī)制芜抒,如果覺得本文對(duì)您有些作用珍策,請(qǐng)?jiān)谙路近c(diǎn)個(gè)贊再走哈~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市宅倒,隨后出現(xiàn)的幾起案子攘宙,更是在濱河造成了極大的恐慌,老刑警劉巖拐迁,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹭劈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡线召,警方通過查閱死者的電腦和手機(jī)链方,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灶搜,“玉大人,你說我怎么就攤上這事工窍「盥簦” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵患雏,是天一觀的道長鹏溯。 經(jīng)常有香客問我,道長淹仑,這世上最難降的妖魔是什么丙挽? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮匀借,結(jié)果婚禮上颜阐,老公的妹妹穿的比我還像新娘。我一直安慰自己吓肋,他們只是感情好凳怨,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著是鬼,像睡著了一般肤舞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上均蜜,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天李剖,我揣著相機(jī)與錄音,去河邊找鬼囤耳。 笑死篙顺,一個(gè)胖子當(dāng)著我的面吹牛偶芍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慰安,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼腋寨,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了化焕?” 一聲冷哼從身側(cè)響起萄窜,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎撒桨,沒想到半個(gè)月后查刻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凤类,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年穗泵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谜疤。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佃延,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夷磕,到底是詐尸還是另有隱情履肃,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布坐桩,位于F島的核電站尺棋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏绵跷。R本人自食惡果不足惜膘螟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碾局。 院中可真熱鬧荆残,春花似錦、人聲如沸净当。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚯瞧。三九已至嘿期,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間埋合,已是汗流浹背备徐。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留甚颂,地道東北人蜜猾。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓秀菱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蹭睡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子衍菱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345