Objective-C是從C發(fā)展出來的語言谤碳,只是在語言層面上加了些關(guān)鍵字和語法旷档。真正讓Objective-C強(qiáng)大的是它的Runtime運(yùn)行時(shí),讓OC在C語言的基礎(chǔ)上增加了面向?qū)ο蠛蛣?dòng)態(tài)特性。
Q1:OC與C語言有什么不同琐谤?
C是靜態(tài)語言檐蚜、面向過程語言
OC是動(dòng)態(tài)語言魄懂、面向?qū)ο笳Z言
因此,OC更加強(qiáng)大闯第。
Q2:C是靜態(tài)語言市栗,OC是從C語言發(fā)展出來的,OC如何實(shí)現(xiàn)動(dòng)態(tài)的咳短?
Runtime(運(yùn)行時(shí))
Q3:什么是Runtime填帽?
- Runtime是為了實(shí)現(xiàn) OC 面向?qū)ο蟆?dòng)態(tài)機(jī)制的一個(gè)庫(kù)咙好。
- 由 C 和匯編語言寫成篡腌。
Q4:Runtime干什么?
OC代碼并不是直接編譯為目標(biāo)語言勾效,OC代碼首先需要編譯器轉(zhuǎn)化為純C語言嘹悼,然后編譯和匯編成目標(biāo)代碼叛甫。
其中,從OC到C語言的轉(zhuǎn)化杨伙,就需要運(yùn)行時(shí)庫(kù)Runtime其监。這個(gè)運(yùn)行時(shí)庫(kù)(Runtime)用來動(dòng)態(tài)得創(chuàng)建類和對(duì)象、進(jìn)行消息傳遞和轉(zhuǎn)發(fā)缀台。
- 將 OC 面向?qū)ο蟮念愞D(zhuǎn)變?yōu)?C 語言面向過程的結(jié)構(gòu)體
- 將 OC 函數(shù)調(diào)用轉(zhuǎn)化為消息傳遞和轉(zhuǎn)發(fā)
- 消息傳遞和轉(zhuǎn)發(fā)的過程棠赛,最終找到合適的C函數(shù)執(zhí)行的過程。
Q5:如何實(shí)現(xiàn)Runtime膛腐?
Runtime核心是消息分發(fā)機(jī)制
Runtime一些核心結(jié)構(gòu)體定義
1. 對(duì)象定義:
struct objc_object {
Class isa;
} *id;
每個(gè)OC對(duì)象的首個(gè)成員是一個(gè)指向Class的指針isa(如果子類中定義了其他對(duì)象睛约,那么追加在后面)。
2. Class定義:
typedef struct objc_class *Class;
Class就是一個(gè)指針哲身,指向一個(gè)objc_class結(jié)構(gòu)體辩涝。
3. objc_class結(jié)構(gòu)體的定義:
struct objc_class {
Class isa; //指針:指向當(dāng)前類的元類(類的類)
Class super_class; //指針:指向當(dāng)前類的父類
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list ** methodLists; //方法列表
struct objc_cache *cache; //cache的方法
struct objc_protocol_list *protocols;
};
- objc_class定義了類的信息,存放了類的元數(shù)據(jù)metadata勘天,其中包括類的元類怔揩、父類、Name脯丝、變量商膊、方法列表、方法cache(用于加速方法查詢)宠进。
- objc_class類中首個(gè)變量也是一個(gè)isa指針晕拆,說明Class也是一個(gè)對(duì)象(類也是一個(gè)對(duì)象)。
- objc_class的isa指針指向的當(dāng)前類的類(元類metaclass)材蹬,保存了當(dāng)前類對(duì)象的元數(shù)據(jù)实幕,類方法定義此處。
- 每個(gè)類僅有一個(gè)元類metaclass堤器,每個(gè)元類僅有一個(gè)metaclass對(duì)象(就是這個(gè)類Class)
- 每個(gè)類對(duì)象中持有了一個(gè)isa指針闸溃,指向這個(gè)對(duì)象的類對(duì)象(類對(duì)象保存了該類的成員方法)整吆;
- 類對(duì)象中的super_class指針指向了這個(gè)類的父類,isa指向該類的元類(元類保存了該類的類方法)圈暗;
- 元類中的super_class指針指向元類的父類掂为。
4. 選擇器Selector
// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
選擇器Selector用于標(biāo)識(shí)一個(gè)方法。從上面代碼中我們可以看出员串,SEL是一個(gè)指向objc_selector結(jié)構(gòu)體的指針勇哗。
struct objc_selector {
char *name;
char *types;
};
objc_selector是一個(gè)結(jié)構(gòu)體,用于標(biāo)識(shí)一個(gè)方法寸齐。用于在類的HashTable找到對(duì)應(yīng)的函數(shù)欲诺。
5. IMP
typedef void (*IMP)(void /* id, SEL, ... */ );
IMP就是一個(gè)函數(shù)指針抄谐,參數(shù)為(id, SEL, ...) 指向函數(shù)所在內(nèi)存地址
6. 方法列表
struct objc_method {
SEL _Nonnull method_name ;
char * method_types;
IMP _Nonnull method_imp ;
};
typedef struct objc_method *Method;
struct objc_method_list {
struct objc_method_list *bsolete;
int method_count;
/* variable length structure */
struct objc_method method_list[1];
};
objc_method結(jié)構(gòu)體保存方法的信息,其中包含SEL和IMP扰法,SEL用來標(biāo)識(shí)一個(gè)方法蛹含,IMP用來指向方法的內(nèi)存地址。
7. 方法緩存
struct objc_cache {
unsigned int mask /* total = mask + 1 */ ;
unsigned int occupied;
Method _Nullable buckets[1];
};
當(dāng) objc_msgSend() 通過一個(gè)類來查找一個(gè)選擇器SEL時(shí)塞颁,它首先會(huì)搜索類緩存浦箱,用于快速查找Method,如果沒找到再遍歷objc_method_list祠锣。
8. 變量列表
struct objc_ivar {
char * ivar_name;
char * ivar_type;
int ivar_offset ;
};
struct objc_ivar_list {
int ivar_count;
/* variable length structure */
struct objc_ivar ivar_list[1];
};
9. 協(xié)議列表
struct objc_protocol_list {
struct objc_protocol_list * next;
long count;
__unsafe_unretained Protocol * list[1];
};
@interface Protocol : NSObject
@end
Protocol也是一個(gè)對(duì)象酷窥。
從上面可以看出:
- Class、SEL伴网、Method都是指向特定結(jié)構(gòu)體的指針蓬推。
- IMP是函數(shù)指針。
小結(jié):本文簡(jiǎn)單介紹了iOS Runtime的一些基本概念澡腾,并分析了runtime的源碼中這些概念的實(shí)現(xiàn)沸伏。
簡(jiǎn)單來說OC在C語言的基礎(chǔ)上定義了一系列的概念(如Class、SEL动分、Method毅糟、IMP),引入了面向?qū)ο罄焦⑾鬟f和轉(zhuǎn)發(fā)機(jī)制留特,從而實(shí)現(xiàn)了Runtime機(jī)制。
參考:
Runtime 源碼