Objective-C 中的类和对象
http://blog.ibireme.com/2013/11/25/objc-object/
Objective-C的runtime是開源的,源碼可以在蘋果官網下載到:objc4。
在objc4-532.2以后,蘋果把NSObject的實現也挪進來了。想要了解NSObject底層實現終于不用去摳GNUstep了~
好了,下面正文:
1.id和Class的定義
runtime里面,聲明了id和Class的類型,簡化一下如下:
| 1 2 3 4 5 6 7 8 9 | 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代表了一個對象。根據上面的聲明,凡是首地址是*isa的struct指針,都可以被認為是objc中的對象。運行時可以通過isa指針,查找到該對象是屬于什么類(Class)。
?
2.運行時的實現方式
根據上面的說法,類對象(Class)同樣也算是對象,那它的isa又是指向了什么呢?為了了解這些東西是怎么回事,這里寫一個簡單的類NyanCat,并且用C重寫一遍,看看編譯器在底層到底是如何實現的。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @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,有一個類方法、一個實例方法。
| 1 | clang -rewrite-objc NyanCat.m |
在終端執行上面這一條語句,讓clang將該類重寫為cpp代碼,我們就能查看到大概底層的實現機制了(實際編譯的文件和這個會有些出入,不同目標架構和不同版本clang也會有不同..權且當參考了)。
?
rewrite后的代碼基本是純C的,稍微整理一下,可以提取出下面這些信息:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | //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;??//協議列表 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里只記錄了類名、類方法列表等。
畫出圖來就是這樣:
舉例來說一下:
| 1 2 | NyanCat *cat = [[NyanCat alloc] init]; [cat nyan1]; |
向cat (instance) 發送消息nyan1時,運行時會通過isa指針查找到NyanCat(Class),這里保存著本類中定義的實例方法的指針。
| 1 | [NyanCat nyan2]; |
向NyanCat(Class)發送消息nyan2時,運行時會通過isa查找到NyanCat(meta-class),這里保存著本類中定義的類方法的指針。
運行時如何利用Chass和meta-class來實現動態消息的,以后在記吧~
3.類的繼承
在_class_t里面,第二個成員是superclass,很明顯這個指針指向了它的父類。運行時可以通過isa和superclass獲取一個類在繼承樹上的完整信息。
為了說明方便,這里把上面的例子稍微改一下:NyanCat : Cat : NSObject 這樣一個繼承樹,畫出圖來就是這樣子的:
?
如上面圖中,跟隨黑線,可以看到isa的指向。運行時,每個對象的isa都不為空,這樣只要是一個id類型的對象,runtime都可以通過訪問首地址偏移(isa)來獲取該對象的信息了。
上圖中跟隨綠線,可以看到superclass的指向。當運行時在搜尋方法、ivar信息時,如果沒有找到信息,則會沿superclass的線查找上去,最終NSObject(根類)的superclass是nil。
如果自己定義了一個根類(比如NSProxy),則這個根類會替換圖中NSObject的位置。
為了驗證上面的說法,可以敲一下代碼看看:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #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 } |
?
?
?
最后吐嘈一下:平時開發時,meta-class基本是用不著接觸的,superclass指針無法訪問,isa指針可能稍后也會隱藏起來(蘋果的動作真多)。。所以上面說得這些,了解一下就好~~
轉載于:https://www.cnblogs.com/feng9exe/p/6041111.html
總結
以上是生活随笔為你收集整理的Objective-C 中的类和对象的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tcpdump命令总结
- 下一篇: [洛谷P1902]刺杀大使