本文github地址 https://github.com/ICZhuang/Runtime 朋友們?nèi)绻矚g收藏即可,不建議轉(zhuǎn)載,筆者會(huì)不定期update文章,github 也會(huì)同步更新,喜歡就star一下吧。
除了前面介紹的三部分(Ivar/Property/Method),基礎(chǔ)的概念部分其實(shí)還應(yīng)包括 Protocol 和 Category。但筆者打算暫時(shí)放下它們。這里想先學(xué)習(xí)Class & Object的原因有以下幾點(diǎn)
- Ivar/Property/Method 三者是我們平常開發(fā)最常見的組成部分,而且足以構(gòu)成一個(gè)完整類;
- 關(guān)于 Ivar/Property/Method 還有一些操作函數(shù),這些函數(shù)實(shí)際是針對(duì)于 Class 或者 Object 的;
- Protocol、 Category 和前面三者基本是差不多的學(xué)習(xí)方法;
關(guān)于 Runtime 的文章太多了,基本上都會(huì)說明三個(gè)關(guān)鍵 類對(duì)象(Class) 元類對(duì)象(Meta Class) 和實(shí)例對(duì)象(Instance),雖然可能會(huì)暈暈乎乎的,但怎么說也有點(diǎn)大概印象,那么在筆者這里只是列舉筆者認(rèn)為的關(guān)鍵點(diǎn)來幫助理解,說白了,也是方便筆者重拾對(duì)Runtime的理解。
還要說明一點(diǎn),要完全剖析 Runtime,筆者認(rèn)為看源碼最合適,奈何筆者不是C、C++大牛,這重任暫時(shí)被擱下了,所以筆者寫的文章也不會(huì)深入的太底層,層面還是來于從網(wǎng)絡(luò)文章和官方文檔加上自己實(shí)踐驗(yàn)證學(xué)習(xí)而來的。
從兩個(gè)結(jié)構(gòu)體開始說起
Runtime 中對(duì)對(duì)象的定義如下所示,是一個(gè) objc_object 結(jié)構(gòu)體,里面擁有一個(gè) Class 類型的 isa 指針
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
但筆者理解,這里的對(duì)象不要狹隘的理解成是實(shí)例對(duì)象,因?yàn)榻酉聛眍惖淖侄我灿幸粋€(gè)isa
相信在接觸 Runtime 之初,大家都聽過這么一句話:“擁有這個(gè)isa指針的都是對(duì)象”,有這樣一個(gè)解釋我覺得很合理:’isa’其實(shí)就是 ‘is a’,這倒是挺形象的描述了這句話。。因?yàn)?,isa 指針就是指向的該對(duì)象所屬的類。
往下查找 Class 類型,它是一個(gè) objc_class 結(jié)構(gòu)體類型指針,objc_class 結(jié)構(gòu)體如下所示
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
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;
#endif
} OBJC2_UNAVAILABLE;
套路來了,這里筆者還是要假裝地提一下這個(gè)問題,方便做牽引和說明,就是:“既然對(duì)象 isa 指向的是所屬的類,怎么類里面還有一個(gè)isa?搞事情???”
無疑,類擁有了 isa 指針,那么類也是一個(gè)對(duì)象,稱為類對(duì)象,相信大家可能聽過或者已經(jīng)了解過了,它在內(nèi)存中就是一個(gè)單例對(duì)象。那既然 isa 是指向其類的指針,那類的 isa 指針如何指向?
答案是,類對(duì)象的 isa 指向的稱為元類(meta class),可以看出,元類也是 Class 類型的??梢哉f類對(duì)象的類型就是它的元類
其實(shí)結(jié)構(gòu)體 objc_object 只是定義了 Objective-C 中對(duì)象應(yīng)該長(zhǎng)什么樣,以此說明類和元類都是對(duì)象。任何繼承與NSObject的類都有一個(gè)'isa'指針,NSObject就是OC層面的‘objc_object’。
內(nèi)存布局
實(shí)例對(duì)象也是對(duì)象,難道它的實(shí)例變量就只有一個(gè)isa?那繼承NSObject后自己定義的實(shí)例變量放在哪里?
這里要先停一下了,推薦大家先看一下這篇博客,了解一個(gè)對(duì)象在內(nèi)存的布局和它與類之間的關(guān)系,將會(huì)有大幫助 因?yàn)椴幌雽懲瑯拥钠?,這里放上博客鏈接 http://www.cnblogs.com/csutanyu/archive/2011/12/12/Objective-C_memory_layout.html
這里附上筆者理解后做的關(guān)于RTModel的內(nèi)存布局,就是指針指來指去。(不知Heap位置放對(duì)了沒有,因?yàn)椴恢纁lass對(duì)象都放在哪,Heap基于筆者對(duì)C的理解)

我們定義的那些類,運(yùn)行時(shí)候加載到內(nèi)存中, 將類中定義的對(duì)象方法存到方法列表的 methodLists 字段中,成員變量存到 ivars 中,遵循的協(xié)議存到 protocols 中,這些都是 objc_class 結(jié)構(gòu)體就已經(jīng)定義的
實(shí)例對(duì)象 instance 可以在內(nèi)存空間允許的情況下創(chuàng)建多個(gè),實(shí)例對(duì)象依據(jù)類(class)對(duì)象而生。但實(shí)例對(duì)象存放的是實(shí)例變量(當(dāng)然包括了父類聲明的成員變量,父類的在前,子類的在后),因?yàn)閕var才是各個(gè)實(shí)例對(duì)象不同的地方,像方法這種共用的就放在類中,否則開辟一個(gè)實(shí)例變量就拷貝一份方法列表,那內(nèi)存會(huì)吃不消的。
調(diào)用對(duì)象方法,就是給實(shí)例對(duì)象發(fā)送消息,通過在它的類中的方法列表 methodLists 找到方法并執(zhí)行。
接著可以說說元類(meta class)了,如上面所述,類(class)的isa指向的就是元類。而且元類的結(jié)構(gòu)跟類的結(jié)構(gòu)是一樣的。只是在元類的方法列表 methodLists 中,存放的是類中定義的 類方法,而類中的 methodLists 存放的是對(duì)象方法。當(dāng)調(diào)用類方法的時(shí)候,通過在元類中找到方法并執(zhí)行。還有關(guān)于 Cache,是關(guān)于方法的緩存,再深究的話就到講實(shí)現(xiàn)上面了,筆者還沒研究那么深呢,哈哈,原諒。

可以發(fā)現(xiàn),元類既然也是 Class 類型,那它也應(yīng)該是類對(duì)象,isa指向它的類。那最終isa指向誰呢?這里筆者不負(fù)責(zé)任的說,上面推薦的博客最下方的圖已經(jīng)比較形象清晰的了。。 或許你還見過那個(gè)文檔中拷出來的圖,跟博客中的是一樣的意思,比如這篇博客也有極大幫助http://blog.csdn.net/wzzvictory/article/details/8592492
總結(jié):
- Runtime 中對(duì)對(duì)象的概念 和我們開發(fā)中念叨的實(shí)例對(duì)象要分清,這里只是OC對(duì)對(duì)象的宏觀的定義;
- 實(shí)例對(duì)象存放著各自的實(shí)例變量,但共用 class 對(duì)象,實(shí)例對(duì)象的 isa 指向它的 class 對(duì)象;
- class 的 isa 指向它的元類對(duì)象 meta class,meta class的 isa 都指向 NSObject meta class;
- class 的 super_class 指向其父類的 class,NSObject class的super_class 指向0x0;
- meta class 的 super_class 指向其父類的 meta class, 但 NSObject meta class 的 super_class 指向它自己的類對(duì)象(class);