Objective-C是一個(gè)面向?qū)ο笳Z(yǔ)言慰技,每一個(gè)對(duì)象都是一個(gè)類(lèi)的實(shí)例阴挣。那類(lèi)和方法調(diào)用的本質(zhì)是什么呢?runtime究竟又是什么呢流纹?這篇文章主要是記錄了解到的相關(guān)知識(shí)。這部分知識(shí)應(yīng)該是OC中最基礎(chǔ)的部分了违诗,對(duì)于深入理解某些知識(shí)還是很重要的漱凝。
runtime
runtime的概念在官方文檔中有介紹。整理如下诸迟,runtime其實(shí)是一個(gè)runtime庫(kù)茸炒,能夠提供OC語(yǔ)言的動(dòng)態(tài)屬性。這個(gè)庫(kù)是開(kāi)源的阵苇,我們可以在GitHub下載它的源碼看看壁公。
源碼中objc.h中有很多基本類(lèi)型的定義,比如對(duì)象和方法:
// 對(duì)象
typedef struct objc_object {
Class isa;
} *id;
// 方法
typedef struct objc_selector *SEL;
typedef id (*IMP)(id, SEL, ...);
開(kāi)頭的第二個(gè)問(wèn)題解決了绅项,接下來(lái)研究第一個(gè)問(wèn)題紊册。這個(gè)問(wèn)題在源碼中也可以找到答案。
對(duì)象
源碼中的Object.h中定義如下:
@interface Object
{
Class isa; /* A pointer to the instance's class structure */
}
isa是一個(gè)指向?qū)嵗念?lèi)結(jié)構(gòu)體的指針快耿,那Class到底是什么類(lèi)型呢囊陡?
源碼中的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;
};
接下來(lái)搞清楚幾個(gè)重要屬性都是什么,
isa:是一個(gè)Class類(lèi)型的指針润努。 每個(gè)Object都有isa指針关斜,指向?qū)ο蟮念?lèi),而Class里也有個(gè)isa的指針, 指向meteClass(元類(lèi))铺浇。元類(lèi)保存了類(lèi)方法的列表痢畜。當(dāng)類(lèi)方法被調(diào)用時(shí),先會(huì)從本身查找類(lèi)方法的實(shí)現(xiàn),如果沒(méi)有丁稀,元類(lèi)會(huì)向他父類(lèi)查找該方法吼拥。同時(shí)注意的是:元類(lèi)(meteClass)也是類(lèi),它也是對(duì)象线衫。元類(lèi)也有isa指針,它的isa指針最終指向的是一個(gè)根元類(lèi)(root meteClass).根元類(lèi)的isa指針指向本身凿可,這樣形成了一個(gè)封閉的內(nèi)循環(huán)。
super_class:指向父類(lèi)授账,沒(méi)有賊為NULL枯跑。
name:類(lèi)的名稱(chēng)
ivars:成員變量的數(shù)組
methods:方法的定義列表,對(duì)象的方法定義都保存在類(lèi)的可變區(qū)域中白热。methodLists是一個(gè)指針的指針敛助,通過(guò)修改該指針指向的指針的值,就可以實(shí)現(xiàn)動(dòng)態(tài)地為某一個(gè)類(lèi)增加成員方法屋确。這也是Category實(shí)現(xiàn)的原理纳击。同時(shí)也說(shuō)明了為什么Category只可為對(duì)象增加成員方法,卻不能增加成員變量
方法調(diào)用
Objective-c是一門(mén)動(dòng)態(tài)語(yǔ)言攻臀,調(diào)用方法的時(shí)候焕数,在運(yùn)行時(shí),動(dòng)態(tài)的查找方法刨啸,然后調(diào)用相應(yīng)的函數(shù)地址堡赔。
SEL
SEL又叫選擇器,是表示一個(gè)方法的selector的指針呜投。Objective-C 在編譯時(shí)加匈,會(huì)根據(jù)方法的名字生成一個(gè)用來(lái)區(qū)分這個(gè)方法的唯一的一個(gè)ID,本質(zhì)上就是一個(gè)字符串仑荐,即Int類(lèi)型的地址雕拼,這個(gè)字符串就是SEL。只要方法名稱(chēng)相同粘招,那么它們的ID就是相同的啥寇。
objc.h中的IMP實(shí)際上就是一個(gè)函數(shù)指針,指向方法實(shí)現(xiàn)的首地址洒扎。
在Objective-C中辑甜,消息直到運(yùn)行時(shí)才綁定到方法實(shí)現(xiàn)上。編譯器會(huì)將消息表達(dá)式[receiver message]轉(zhuǎn)化為一個(gè)消息函數(shù)的調(diào)用袍冷,即objc_msgSend磷醋,將消息接收者和方法名作為其基礎(chǔ)參數(shù),如以下所示:
objc_msgSend(receiver, selector)
當(dāng)消息發(fā)送給一個(gè)對(duì)象時(shí)胡诗,objc_msgSend通過(guò)對(duì)象的isa指針獲取到類(lèi)的結(jié)構(gòu)體邓线,然后在methods里面查找方法的selector淌友。如果沒(méi)有找到selector,則找到其父類(lèi)骇陈,并在父類(lèi)的分發(fā)表里面查找震庭。依此,會(huì)一直沿著類(lèi)的繼承體系到達(dá)NSObject類(lèi)你雌。一旦定位到selector器联,函數(shù)就獲取到了實(shí)現(xiàn)的入口點(diǎn),并傳入相應(yīng)的參數(shù)來(lái)執(zhí)行方法的具體實(shí)現(xiàn)婿崭。如果最后沒(méi)有定位到selector拨拓,則會(huì)走消息轉(zhuǎn)發(fā)流程。
為了加速消息的處理氓栈,運(yùn)行時(shí)系統(tǒng)緩存使用過(guò)的selector及對(duì)應(yīng)的方法的地址千元。
參考文章:
Objective-C對(duì)象模型及應(yīng)用
OC Runtime第一篇---類(lèi)與對(duì)象
Objective-C Runtime 運(yùn)行時(shí)之三:方法與消息