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

本文章轉自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)機制了(實際編譯的文件和這個會有些出入,不同目標架構和不同版本clang也會有不同..權且當參考了)。

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

//Class的實際結構
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指針可能稍后也會隱藏起來(蘋果的動作真多)。。所以上面說得這些,了解一下就好~~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

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