目前iOS中,objc_class與objc_object使用的是后兩個(gè)定義。
struct objc_class : objc_object {
? ? // Class ISA;
? ? Class superclass;
? ? cache_t cache;?????????????// formerly cache pointer and vtable
? ? class_data_bits_t bits;????// class_rw_t * plus custom rr/alloc flags
}
struct objc_object {
? ? private:
? ? isa_t isa;
}
這些結(jié)構(gòu)體代表了類和對象在runtime中的數(shù)據(jù)結(jié)構(gòu)
typedef struct objc_class *Class;
typedef struct objc_object *id;
使用重定義,Class 指向objc_class結(jié)構(gòu)體的指針,id??指向objc_object結(jié)構(gòu)體的指針
id obj;
Class cls;
定義的均是的指針變量
struct objc_class : objc_object,這說明每一個(gè)類實(shí)際上也是一個(gè)對象,有一個(gè)is a的指針
每一個(gè)對象都有一個(gè)is a的指針,通過該指針,我們能找到對象所屬類。每一個(gè)類也有一個(gè)is a的指針,也是一個(gè)對象,那么,它也必須是另一個(gè)類的實(shí)例,這個(gè)類就是元類。元類也是一個(gè)對象,那么元類的is a指針又指向了哪里?
為了設(shè)計(jì)上的完整,所有的元類的is a指針都會(huì)指向一個(gè)根元類,根元類本身的is a指針指向自己,這樣就形成了一個(gè)閉環(huán)。圖片參考 iOS開發(fā)進(jìn)階 p217
通過上圖,我們可以得出以下結(jié)論
1 類的類是元類
2 類的根類是NSObjet,NSObject的父類是nil
3 元類同樣存在繼承關(guān)系,元類的父類等價(jià)于父類的元類(類方法查找過程中的必須)
4 元類的根類是NSObjet的元類,NSObjet的元類isa指向自身。
5 NSObjet的元類的父類是NSObjet
每個(gè)類的類對象和元類對象 都僅有一個(gè)
消息發(fā)送機(jī)制,是對對象發(fā)送消息。也就是方法
@interface NSObject {
? ? Class isa??OBJC_ISA_AVAILABILITY;
}
由于繼承關(guān)系,每個(gè)類都會(huì)有一個(gè)is a指針。
Person *ps = [Person new];
之前我的理解是創(chuàng)建一個(gè)結(jié)構(gòu)體的指針(Class cls,Class經(jīng)過重定義,創(chuàng)建出的變量,是指向objc_class的指針)。后來,又想到了C++中類和結(jié)構(gòu)體的區(qū)別,然后整個(gè)人就懵逼了。
這里,是一個(gè)疑問,OC中的類本質(zhì)是不是一個(gè)結(jié)構(gòu)體。這里,一些解釋是類比著結(jié)構(gòu)體,比如我們每創(chuàng)建一個(gè)類實(shí)例,就像定義了一個(gè)對應(yīng)結(jié)構(gòu)的結(jié)構(gòu)體變量,可能會(huì)有些不當(dāng),但有助于理解。在Runtime之外,還是說類和對象比較合適點(diǎn)。
類中定義了實(shí)例方法,元類中定義了類方法。
實(shí)例方法的調(diào)用規(guī)則是,根據(jù)is a指針找到類,如果該類沒有定義一個(gè)方法的實(shí)現(xiàn),則根據(jù)繼承關(guān)系,向它的父類繼續(xù)查找,
類方法的調(diào)用原則,當(dāng)一個(gè)類方法被調(diào)用時(shí),根據(jù)is a指針找到元類,元類首先會(huì)查找自身有沒有該類方法的實(shí)現(xiàn),如果沒有,則元類會(huì)向它的父類查找該方法,這樣可以一直找到繼承鏈的頭。
所以,為了保證父類的類方法在子類中被調(diào)用,所有子類的元類都會(huì)繼承父類的元類,換而言之,類對象和元類對象有著同樣的繼承關(guān)系。
雖然有些東西被廢棄了,但是原理是相通的,我們?nèi)阅軓闹蝎@得一些有價(jià)值的信息。
struct objc_cache *cache????????????????OBJC2_UNAVAILABLE;??// 方法緩存
例如,方法緩存。這里先說下相通的原理,后面會(huì)詳細(xì)說道,優(yōu)化后的緩存
cache 為方法調(diào)用的性能進(jìn)行優(yōu)化。通俗地講,每當(dāng)實(shí)例對象接收到一個(gè)消息時(shí),它不會(huì)直接在isa指向的類的方法列表中遍歷查找能夠響應(yīng)消息的方法,因?yàn)檫@樣效率太低了,而是優(yōu)先在Cache中查找。Runtime 系統(tǒng)會(huì)把被調(diào)用的方法存到Cache中(理論上講一個(gè)方法如果被調(diào)用,那么它有可能今后還會(huì)被調(diào)用)如果cache沒有,才去methodLists中查找方法。這樣,對于那些經(jīng)常用到的方法的調(diào)用,但提高了調(diào)用的效率