總結(jié)性文章凤薛,如有問題丢习,請評論
從以下幾個維度分析
1.對象的分類
- 首先按分類來說辛萍,OC對象分為實例對象想暗、類對象诫给、元類對象三種毒姨。
他們的底層實現(xiàn)都是結(jié)構(gòu)體.
2.內(nèi)部實現(xiàn)
- 實例對象
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
Class的內(nèi)部實現(xiàn)
typedef struct objc_class *Class;
所以ISA是一個指向結(jié)構(gòu)體的指針變量
當(dāng)繼承發(fā)生時
struct NSobject_imp{
Class imp;
};
struct Person {
struct NSobject_imp imp_isa;
int _age;
int _num;
int _on;
};
通俗理解,生成的person實例對象中衣陶,包含三個ivar + NSObject的ISA指針
實例對象的結(jié)構(gòu)如下:
- ISA //指向父類的指針
- _ivar //成員變量
- _ivar //成員變量
- _ivar //成員變量
類對象class
通過xcode查看的類對象已經(jīng)過時,下邊是之前的定義财饥,最新的定義可以查看objc的源碼墩衙,在下邊列出幾個重要的點
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
新版
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
最新版的ISA被注釋掉了躺孝,不要被迷惑享扔,只要是對象,就會有ISA植袍,實際是objc_class繼承于objc_object
而...
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
然后展開class_data_bits_t里邊public的 class_rw_t, 看通過 rw可以了解惧眠,這部分是可以讀寫的
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint16_t version;
uint16_t witness;
const class_ro_t *ro; //不可寫部分
method_array_t methods; //方法列表
property_array_t properties;// 屬性列表
protocol_array_t protocols; //協(xié)議列表
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
}
這是 class_ro_t 可讀不可寫的部分
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize; //實例的大小
#ifdef __LP64__
uint32_t reserved;
#endif
t uint8_t * ivarLayout;
const char * name; //類名
method_list_t * baseMethodList; //最初的方法列表
protocol_list_t * baseProtocols; //最初的協(xié)議列表
const ivar_list_t * ivars; //成員變量列表
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
}
通過上述幾個機(jī)構(gòu)提可以看出,類對象的基本結(jié)構(gòu)如下
- ISA // 指向元類指針
- superclass //指向父類的指針
- cache //方法緩存列表于个,注意是對象方法
- bits //里邊有基本的可變的一堆屬性和不可變的一堆屬性
針對bits里邊可變不可變的屬性做個補(bǔ)充:
- method 和 protocol 這些通過運行時可以動態(tài)添加氛魁;properties可以在分類中添加(只不過值是存儲在一個全局的散列表中的)
- ivars這個是不可變的,也就是說厅篓,不能向一個已經(jīng)創(chuàng)建好的類中添加ivar秀存,這是因為,在實例化實例對象的時候羽氮,內(nèi)存大小是固定的或链。(instanceSize)
實例結(jié)構(gòu)體中包含的就是ISA指針和ivars的列表。
元類對象
元類對象是類對象的一種档押,內(nèi)部結(jié)構(gòu)和類對象一樣澳盐,在創(chuàng)建類對象的時候,會同時創(chuàng)建一個元類對象出來令宿。
只不過內(nèi)部存儲的值和類對象是不一樣的叼耙,元類對象中存儲的是類方法。
- ISA // 指向基類元類指針(注:此處的ISA指針直接指向NSObject的元類)
- superclass //指向父類的元類的指針
- cache //方法緩存列表粒没,注意類象方法
- bits //類方法
總結(jié):起始根據(jù)這三種對象筛婉,體現(xiàn)了程序的分層設(shè)計的原則,最上層包含的是成員變量癞松、下一層包含各種方法和緩存爽撒、再進(jìn)一層就是只有類才能調(diào)用的類方法。
3.占用空間的大小
我們創(chuàng)建一個實例對象响蓉,占用的內(nèi)存空間的大小是怎么樣的硕勿,找到最上邊實例的結(jié)構(gòu)體樣式。
- ISA //指向父類的指針
- _ivar //成員變量
- _ivar //成員變量
- _ivar //成員變量
我們可以看到厕妖,包含一個ISA指針首尼,還有不等的ivar,占用的大小可以直接算出言秸,指針變量8個字節(jié)软能,int 類型 4個字節(jié)... 相加就得出了。
但是注意:結(jié)構(gòu)體在創(chuàng)建的時候举畸,有內(nèi)存對齊的概念查排,必須是8的整數(shù)倍,也就是當(dāng)內(nèi)存占用20個字節(jié)抄沮,會給你分配24個字節(jié)跋核。
C函數(shù)還有一層內(nèi)存對齊的概念岖瑰,他分配內(nèi)存大小是16的整數(shù)倍
4.方法調(diào)用
直接拿網(wǎng)上的圖
先看ISA 和 superclass這兩個指針的指向
ISA - > 父類
父類ISA - >元類
元類ISA - > Root Meta Class
Subclass 的superclass指針 - > Superclass
Superclass 的 superclass指針 - > NSObject
對象方法:根據(jù)ISA指針找到自己的父類-- >查找父類cache緩存 -->查找父類methodlist --> 根據(jù)superclass指針 -- > Superclass的cache --- > Superclass的methodlist ---> NSObject...
類方法:根據(jù)ISA指針找到Metaclass的cache -- > Metaclass 的methodlist -- > 根據(jù)superclass指針周到 Superclass Meta的cache ....
其他補(bǔ)充
1.關(guān)于ISA指針中存儲的地址不是類對象首地址的原因
由于在新版ISA指針做了優(yōu)化,8個字節(jié) 64位的存儲空間砂代,不僅存儲指向類對象的地址蹋订,還保存了一些標(biāo)志位信息,包括是否有關(guān)聯(lián)對象刻伊、是否有弱引用露戒、引用計數(shù)存儲等。所以要取出這個地址還是要 & 上下邊的地址捶箱。
2.類方法在尋找的時候智什,找到NSObject的元類中,如果還是沒有丁屎,還會去NSObject類中尋找是否有相同符號的對象方法荠锭。
3.獲取元類的方式object_getClass([NSObject class]);傳遞一個類對象進(jìn)去,就可以獲取晨川。