Objective-C運行時原理(一):類和對象

本文章轉(zhuǎn)自Objective-C 中的類和對象
Objective-C的runtime是開源的止状,源碼可以在蘋果官網(wǎng)下載到:objc4

好了阳仔,下面正文:

1.id和Class的定義

runtime里面忧陪,聲明了idClass的類型,簡化一下如下:

struct objc_class {
    struct objc_class *isa;
};
struct objc_object {
    struct objc_class *isa;
};

typedef struct objc_class *Class; //類  (class object)
typedef struct objc_object *id;   //對象 (instance of class)

在objc中近范,id代表了一個對象嘶摊。根據(jù)上面的聲明,凡是首地址是*isa的struct指針评矩,都可以被認為是objc中的對象叶堆。運行時可以通過isa指針,查找到該對象是屬于什么類(Class)斥杜。

2.運行時的實現(xiàn)方式

根據(jù)上面的說法虱颗,類對象(Class)同樣也算是對象,那它的isa又是指向了什么呢蔗喂?為了了解這些東西是怎么回事忘渔,這里寫一個簡單的類NyanCat,并且用C重寫一遍缰儿,看看編譯器在底層到底是如何實現(xiàn)的畦粮。

@interface NyanCat : NSObject {
    int age;
    NSString *name;
}
- (void)nyan;
+ (void)nyan;
@end

@implementation NyanCat
- (void)nyan1 {
    printf("instance nyan~");
}
+ (void)nyan2 {
    printf("class nyan~");
}
@end

上面是一個簡單的類,有兩個instance variable乖阵,有一個類方法宣赔、一個實例方法。

clang -rewrite-objc NyanCat.m

在終端執(zhí)行上面這一條語句瞪浸,讓clang將該類重寫為cpp代碼儒将,我們就能查看到大概底層的實現(xiàn)機制了(實際編譯的文件和這個會有些出入,不同目標架構(gòu)和不同版本clang也會有不同..權(quán)且當參考了)对蒲。

rewrite后的代碼基本是純C的钩蚊,稍微整理一下贡翘,可以提取出下面這些信息:

//Class的實際結(jié)構(gòu)
struct _class_t {
    struct _class_t *isa;        //isa指針
    struct _class_t *superclass; //父類
    void *cache;
    void *vtable;
    struct _class_ro_t *ro;     //Class包含的信息
};

//Class包含的信息
struct _class_ro_t {
    unsigned int flags;
    unsigned int instanceStart;
    unsigned int instanceSize;
    unsigned int reserved;
    const unsigned char *ivarLayout;
    const char *name;                                 //類名
    const struct _method_list_t *baseMethods;         //方法列表
    const struct _objc_protocol_list *baseProtocols;  //協(xié)議列表
    const struct _ivar_list_t *ivars;                 //ivar列表
    const unsigned char *weakIvarLayout;
    const struct _prop_list_t *properties;            //屬性列表
};

 //NyanCat(meta-class)
struct _class_t OBJC_METACLASS_$_NyanCat  = {
    .isa        = &OBJC_METACLASS_$_NSObject,
    .superclass = &OBJC_METACLASS_$_NSObject,
    .cache      = (void *)&_objc_empty_cache,
    .vtable     = (void *)&_objc_empty_vtable,
    .ro         = &_OBJC_METACLASS_RO_$_NyanCat, //包含了類方法等
};

//NyanCat(Class)
struct _class_t OBJC_CLASS_$_NyanCat = {
    .isa        = &OBJC_METACLASS_$_NyanCat,   //此處isa指向meta-class
    .superclass = &OBJC_CLASS_$_NSObject,
    .superclass = (void *)&_objc_empty_cache,
    .vtable     = (void *)&_objc_empty_vtable,
    .ro         = &_OBJC_CLASS_RO_$_NyanCat,   //包含了實例方法 ivar信息等
};

typedef struct objc_object NyanCat;   //定義NyanCat類型
//更詳細的不貼代碼了..

所有NyanCat的實例的isa都指向了NyanCat(Class)
NyanCat(Class)是一個全局變量两疚,其中記錄了類名床估、成員變量信息含滴、property信息诱渤、protocol信息和實例方法列表等。
NyanCat(Class)的isa指向了全局變量NyanCat(meta-class)谈况,meta-class里只記錄了類名勺美、類方法列表等。
畫出圖來就是這樣:


舉例來說一下:

NyanCat *cat = [[NyanCat alloc] init];
[cat nyan1];

向cat (instance) 發(fā)送消息nyan1時碑韵,運行時會通過isa指針查找到NyanCat(Class)赡茸,這里保存著本類中定義的實例方法的指針。

[NyanCat nyan2];

向NyanCat(Class)發(fā)送消息nyan2時祝闻,運行時會通過isa查找到NyanCat(meta-class)占卧,這里保存著本類中定義的類方法的指針诗力。

運行時如何利用Class和meta-class來實現(xiàn)動態(tài)消息的献宫,以后在記吧~

3.類的繼承

在_class_t里面除嘹,第二個成員是superclass强挫,很明顯這個指針指向了它的父類裳凸。運行時可以通過isa和superclass獲取一個類在繼承樹上的完整信息农曲。
為了說明方便膝宁,這里把上面的例子稍微改一下:NyanCat : Cat : NSObject 這樣一個繼承樹靖榕,畫出圖來就是這樣子的:



如上面圖中蓖谢,跟隨黑線捂蕴,可以看到isa的指向。運行時闪幽,每個對象的isa都不為空啥辨,這樣只要是一個id類型的對象,runtime都可以通過訪問首地址偏移(isa)來獲取該對象的信息了盯腌。

上圖中跟隨綠線委可,可以看到superclass的指向。當運行時在搜尋方法腊嗡、ivar信息時着倾,如果沒有找到信息,則會沿superclass的線查找上去燕少,最終NSObject(根類)的superclass是nil卡者。

如果自己定義了一個根類(比如NSProxy),則這個根類會替換圖中NSObject的位置客们。

為了驗證上面的說法崇决,可以敲一下代碼看看:

#import "NyanCat.h"
#import <objc/runtime.h>
#import <objc/objc.h>

void test() {
    NyanCat *cat = [[NyanCat alloc] init];

    Class cls = object_getClass(cat); //NyanCat(Class)
    class_getName(cls);               //"NyanCat"
    class_isMetaClass(cls);           //NO

    Class meta = object_getClass(cls); //NyanCat(meta-class)
    class_getName(meta);               //"NyanCat"
    class_isMetaClass(cls);            //YES

    Class meta_meta = object_getClass(meta); //NSObject(meta-class)
    class_getName(meta_meta);                //"NSObject"
    class_isMetaClass(meta_meta);            //YES
}

最后吐嘈一下:平時開發(fā)時材诽,meta-class基本是用不著接觸的,superclass指針無法訪問恒傻,isa指針可能稍后也會隱藏起來(蘋果的動作真多)脸侥。。所以上面說得這些盈厘,了解一下就好~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末睁枕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子沸手,更是在濱河造成了極大的恐慌外遇,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件契吉,死亡現(xiàn)場離奇詭異跳仿,居然都是意外死亡,警方通過查閱死者的電腦和手機捐晶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進店門菲语,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惑灵,你說我怎么就攤上這事山上。” “怎么了泣棋?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵胶哲,是天一觀的道長。 經(jīng)常有香客問我潭辈,道長鸯屿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任把敢,我火速辦了婚禮寄摆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘修赞。我一直安慰自己婶恼,他們只是感情好,可當我...
    茶點故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布柏副。 她就那樣靜靜地躺著勾邦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪割择。 梳的紋絲不亂的頭發(fā)上眷篇,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天,我揣著相機與錄音荔泳,去河邊找鬼蕉饼。 笑死虐杯,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的昧港。 我是一名探鬼主播擎椰,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼创肥!你這毒婦竟也來了达舒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤瓤的,失蹤者是張志新(化名)和其女友劉穎休弃,沒想到半個月后吞歼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體圈膏,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年篙骡,在試婚紗的時候發(fā)現(xiàn)自己被綠了稽坤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡糯俗,死狀恐怖尿褪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情得湘,我是刑警寧澤杖玲,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站淘正,受9級特大地震影響摆马,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸿吆,卻給世界環(huán)境...
    茶點故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一囤采、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惩淳,春花似錦蕉毯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至激蹲,卻和暖如春棉磨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背托呕。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工含蓉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留频敛,地道東北人。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓馅扣,卻偏偏與公主長得像斟赚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子差油,可洞房花燭夜當晚...
    茶點故事閱讀 45,937評論 2 361

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