Objective-C是一個面向?qū)ο笳Z言,每一個對象都是一個類的實例。那類和方法調(diào)用的本質(zhì)是什么呢?runtime究竟又是什么呢?這篇文章主要是記錄了解到的相關知識。這部分知識應該是OC中最基礎的部分了,對于深入理解某些知識還是很重要的。
runtime
runtime的概念在官方文檔中有介紹。整理如下,runtime其實是一個runtime庫,能夠提供OC語言的動態(tài)屬性。這個庫是開源的,我們可以在GitHub下載它的源碼看看。
源碼中objc.h中有很多基本類型的定義,比如對象和方法:
// 對象
typedef struct objc_object {
Class isa;
} *id;
// 方法
typedef struct objc_selector *SEL;
typedef id (*IMP)(id, SEL, ...);
開頭的第二個問題解決了,接下來研究第一個問題。這個問題在源碼中也可以找到答案。
對象
源碼中的Object.h中定義如下:
@interface Object
{
Class isa; /* A pointer to the instance's class structure */
}
isa是一個指向?qū)嵗念惤Y構體的指針,那Class到底是什么類型呢?
源碼中的objc_class.h中定義如下:
struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
#if defined(Release3CompatibilityBuild)
struct objc_method_list *methods; //Objective-C 2.0
#else
struct objc_method_list **methodLists; //Objective-C 1.0
#endif
struct objc_cache *cache;
struct objc_protocol_list *protocols;
};
接下來搞清楚幾個重要屬性都是什么,
isa:是一個Class類型的指針。 每個Object都有isa指針,指向?qū)ο蟮念?,而Class里也有個isa的指針, 指向meteClass(元類)。元類保存了類方法的列表。當類方法被調(diào)用時,先會從本身查找類方法的實現(xiàn),如果沒有,元類會向他父類查找該方法。同時注意的是:元類(meteClass)也是類,它也是對象。元類也有isa指針,它的isa指針最終指向的是一個根元類(root meteClass).根元類的isa指針指向本身,這樣形成了一個封閉的內(nèi)循環(huán)。

super_class:指向父類,沒有賊為NULL。
name:類的名稱
ivars:成員變量的數(shù)組
methods:方法的定義列表,對象的方法定義都保存在類的可變區(qū)域中。methodLists是一個指針的指針,通過修改該指針指向的指針的值,就可以實現(xiàn)動態(tài)地為某一個類增加成員方法。這也是Category實現(xiàn)的原理。同時也說明了為什么Category只可為對象增加成員方法,卻不能增加成員變量
方法調(diào)用
Objective-c是一門動態(tài)語言,調(diào)用方法的時候,在運行時,動態(tài)的查找方法,然后調(diào)用相應的函數(shù)地址。
SEL
SEL又叫選擇器,是表示一個方法的selector的指針。Objective-C 在編譯時,會根據(jù)方法的名字生成一個用來區(qū)分這個方法的唯一的一個ID,本質(zhì)上就是一個字符串,即Int類型的地址,這個字符串就是SEL。只要方法名稱相同,那么它們的ID就是相同的。
objc.h中的IMP實際上就是一個函數(shù)指針,指向方法實現(xiàn)的首地址。
在Objective-C中,消息直到運行時才綁定到方法實現(xiàn)上。編譯器會將消息表達式[receiver message]轉化為一個消息函數(shù)的調(diào)用,即objc_msgSend,將消息接收者和方法名作為其基礎參數(shù),如以下所示:
objc_msgSend(receiver, selector)

當消息發(fā)送給一個對象時,objc_msgSend通過對象的isa指針獲取到類的結構體,然后在methods里面查找方法的selector。如果沒有找到selector,則找到其父類,并在父類的分發(fā)表里面查找。依此,會一直沿著類的繼承體系到達NSObject類。一旦定位到selector,函數(shù)就獲取到了實現(xiàn)的入口點,并傳入相應的參數(shù)來執(zhí)行方法的具體實現(xiàn)。如果最后沒有定位到selector,則會走消息轉發(fā)流程。
為了加速消息的處理,運行時系統(tǒng)緩存使用過的selector及對應的方法的地址。
參考文章:
Objective-C對象模型及應用
OC Runtime第一篇---類與對象
Objective-C Runtime 運行時之三:方法與消息