一枣购、 OC的實例
實例或者說是對象實例本質(zhì)是一個結(jié)構(gòu)體:
typedef struct objc_object {
Class isa;
} *id;
而每一個對象都有一個類嬉探,而對象中的isa指針,指向?qū)ο笏鶎俚念悺?br> *id是一個objc_object結(jié)構(gòu)類型的指針棉圈。該類型的對象可以轉(zhuǎn)換為任何一種對象涩堤,類似于C語言中void 指針類型的作用(objc.h)。id 類型是iOS中一種特殊的動態(tài)數(shù)據(jù)類型
二分瘾、類
OC中的類也是對象胎围,類的本質(zhì)是結(jié)構(gòu)體。類對象是由程序員定義并在運行時由編譯器創(chuàng)建的德召,它沒有自己的實例變量白魂,這里需要注意的是類的成員變量和實例方法列表是屬于實例對象的,但其存儲于類對象當中的上岗。
OC中objc_class結(jié)構(gòu)體是繼承自objc_object的福荸。
typedef struct objc_class *Class;
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父類
const char *name OBJC2_UNAVAILABLE; // 類名
long version OBJC2_UNAVAILABLE; // 類的版本信息,默認為0
long info OBJC2_UNAVAILABLE; // 類信息肴掷,供運行期使用的一些位標識
long instance_size OBJC2_UNAVAILABLE; // 該類的實例變量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變量列表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定義的列表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法緩存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;
結(jié)構(gòu)體中:類的isa指針指向其所屬的類敬锐,即元類。
- super_class為該類所繼承的父類對象捆等,如果該類已經(jīng)是最頂層的根類(如NSObject或NSProxy), 則 super_class為NULL滞造。
- info為運行期使用的一些位標識,比如:CLS_CLASS (0x1L)表示該類為普通類, CLS_META (0x2L)則表示該類為元類栋烤。
- methodLists用來存放方法列表明郭,根據(jù)info中的標識信息,當該類為普通類時薯定,存儲的方法為實例方法瞳购;如果是元類則存儲的類方法。
- cache用于緩存最近使用的方法年堆。系統(tǒng)在調(diào)用方法時會先去cache中查找,在沒有查找到時才會去methodLists中遍歷獲取需要的方法芽狗。
三童擎、元類
元類是描述類對象的類攻晒,每個類都有自己的元類。類對象objc_class中的isa指向元類捕透。元類中存儲類對象調(diào)用的方法碴萧,即類對象方法列表。元類的結(jié)構(gòu)體也是struct objc_class虎谢。
四曹质、分類category
分類的本質(zhì)是category_t的結(jié)構(gòu)體
typedef struct category_t {
const char *name; // 類名
classref_t cls; // 類
struct method_list_t *instanceMethods; // category中所有給類添加的實例方法的列表
struct method_list_t *classMethods; // category中所有添加的類方法的列表
struct protocol_list_t *protocols; // category實現(xiàn)的所有協(xié)議的列表
struct property_list_t *instanceProperties; // category中添加的所有屬性列表
} category_t;
category被附加到類上面是在map_images的時候發(fā)生的羽德,在new-ABI的標準下,_objc_init里面的調(diào)用的map_images最終會調(diào)用objc-runtime-new.mm里面的_read_images方法
1)章蚣、把category的實例方法姨夹、協(xié)議以及屬性添加到類上
2)、把category的類方法和協(xié)議添加到類的metaclass上
五峭沦、分類和類擴展
1吼鱼、類擴展可以增加方法和變量
2、類擴展的方法不實現(xiàn)菇肃,編譯器會報警。但是分類的方法不被實現(xiàn)編譯器是不會有警告的驶忌。這是因為類擴展是在編譯階段被添加到類中的笑跛,類別是在運行時被添加到類中的。
3几苍、類擴展沒有獨立的實現(xiàn)部分(@implementation部分)
4陈哑、定義在.m文件中的類擴展方法是私有的
六、元類的本質(zhì)
Objective-C 中的類也是對象刽宪,它也是某個類的實例界酒,這個類我們稱之為元類(metaclass)。
因此庇谆,我們也可以通過調(diào)用類方法凭疮,比如 [NSObject new],給類對象發(fā)送消息寞肖。同樣的材鹦,類對象能否響應(yīng)這個消息也要通過 isa 找到類對象所屬的類(元類)才能知道。也就是說桶唐,實例方法是保存在類中的尤泽,而類方法是保存在元類中的。
那元類也是對象嗎熊咽?是的話那它又是什么類的實例呢?是的横殴,沒錯卿拴,元類也是對象(元類對象),元類也是某個類的實例文狱,這個類我們稱之為根元類(root metaclass)瞄崇。不過,有一點比較特殊苏研,那就是所有的元類所屬的類都是同一個根元類(當然根元類也是元類腮郊,所以它所屬的類也是根元類,即它本身)纹蝴。根元類指的就是根類的元類踪少,具體來說就是根類 NSObject 對應(yīng)的元類。
因此援奢,理論上我們也可以給元類發(fā)送消息集漾,但是 Objective-C 傾向于隱藏元類,不想讓大家知道元類的存在纬霞。元類是為了保持 Objective-C 對象模型在設(shè)計上的完整性而引入的驱显,比如用來保存類方法等瞳抓,它主要是用來給編譯器使用的伏恐。
總結(jié):
所以實例對象的結(jié)構(gòu)體指針isa指向其類對象翠桦,類對象的結(jié)構(gòu)體指針isa指向其元類對象。
類對象的superClass指向其父類销凑,如果該類為根類則superClass值為nil。
元類的isa指針指向根元類茵乱,如果該元類為根元類則元類的isa指針指向其自身瓶竭。
元類的supreClass指向父元類渠羞,如根元類則指向該根類