1. 什么是Runtime
Runtime又叫運(yùn)行時(shí),是一套C語言的API。 我們平時(shí)編寫的OC代碼,底層都是基于它來實(shí)現(xiàn)的。Runtime是一門動(dòng)態(tài)語言,它會(huì)將一些工作放在代碼運(yùn)行時(shí)才處理而并非在編譯時(shí)處理。
2. Runtime相關(guān)名詞介紹
SEL
是selector在Objc中的表示,selector是方法選擇器。
id
id是一個(gè)參數(shù)類型,它是指向某個(gè)類的實(shí)例的指針。定義如下:
typedef struct objc_object *id;
我們在看看objc_object的定義
struct objc_object { Class isa; };
從以上定義,看一看到objc_object結(jié)構(gòu)體包含一個(gè)isa指針,根據(jù)isa指針就可以找到對象所屬的類。
注意:isa指針在代碼運(yùn)行時(shí)并不總指向?qū)嵗龑ο笏鶎俚念愋停圆荒芤揽克鼇泶_定類型。要想確定類型還是需要用對象的-class方法。
Class
typedef struct objc_class *Class;
Class其實(shí)是指向objc_class結(jié)構(gòu)體的指針,
Object_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è)每個(gè)參數(shù)的含義:
isa: 是一個(gè)結(jié)構(gòu)體類型的指針,指向該對象的類,而類中也有個(gè)isa指針,指向meteClass(元類),在元類中保存了類方法的列表。在元類中也有個(gè)isa指針,它指向根元類。
super_class: 父類,如果該類已經(jīng)是最頂層的根類,那么那為NULL。
** version: 類的版本信息, 默認(rèn)為0。
info: 供運(yùn)行期使用的一些位標(biāo)識(shí)。
** instance_size:該類的實(shí)例變量大小。
** ivars: 成員變量數(shù)組。
** methodLists: 方法名
** cache**:為方法調(diào)用的性能進(jìn)行優(yōu)化。
或許你已經(jīng)注意到了,objc_class中也有一個(gè)isa指針,這說明Objc類本身也是一個(gè)對象。為了處理類和對象的關(guān)系,Runtime庫創(chuàng)建了一種叫做Meta Class(元類)的東西,類對象所屬的類就叫做元類。我們所熟悉的類方法,就源自Meta Class,我們可以理解為類方法就是類對象的實(shí)例方法。所有的元類都指向一個(gè)根元類Root Meta Class。
Method
類中某個(gè)方法的類型
typedef struct objc_method *Method;
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
objc_method 存儲(chǔ)了方法名,方法類型和方法實(shí)現(xiàn):
- 方法名類型為SEL
- 方法類型method_types是個(gè)char指針,存儲(chǔ)方法的參數(shù)類型和返回值類型。
- method_imp指向了方法的實(shí)現(xiàn),本質(zhì)是一個(gè)函數(shù)指針。
IMP
IMP在objc.h中的定義是:
typedef id (*IMP)(id, SEL, ...);
它是一個(gè)函數(shù)指針,這是由編譯器生成的。當(dāng)你發(fā)起一個(gè)Objc消息時(shí),最終它會(huì)執(zhí)行哪段代碼,就是由這個(gè)函數(shù)指針指定的。函數(shù)實(shí)現(xiàn)由它定。
Cache
定義如下:
typedef struct objc_cache *Cache
struct objc_cache {
unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method buckets[1] OBJC2_UNAVAILABLE;
};
Cache為方法調(diào)用的性能做了些優(yōu)化,當(dāng)實(shí)例對象接收到一個(gè)消息時(shí),它不會(huì)直接在isa指針指向的類的方法列表中遍歷查找能夠響應(yīng)的方法,因?yàn)槊看味家檎倚侍土?,?huì)優(yōu)先在Cache中查找。Runtime系統(tǒng)會(huì)把被調(diào)用過的方法存到Cache中,如果一個(gè)方法被調(diào)用,下次查找的時(shí)候就會(huì)效率更高。
3. Runtime能干什么
OC是一門動(dòng)態(tài)語言,動(dòng)態(tài)意味著我們在方法調(diào)用的時(shí)候才去查找該方法并調(diào)用執(zhí)行,所以我們可以在方法被調(diào)用時(shí)做一些事情。
3.1 發(fā)送消息
方法調(diào)用的本質(zhì),就是讓對象發(fā)送消息。
3.2 交換方法
系統(tǒng)自帶的方法功能不夠用時(shí),可以給系統(tǒng)方法進(jìn)行功能擴(kuò)展,并且保持原有的功能。
3.3 動(dòng)態(tài)添加方法
如果一個(gè)類方法非常多,當(dāng)加載到內(nèi)存的時(shí)候會(huì)比較耗費(fèi)資源,需要給每個(gè)方法生成映射表,可以使用動(dòng)態(tài)給某個(gè)類添加方法解決。如經(jīng)典面試題:有沒有使用performSelctor,其實(shí)主要是想問你有沒有動(dòng)態(tài)添加過方法。
3.4 給分類添加屬性
給一個(gè)分類聲明屬性,其實(shí)本質(zhì)就是給這個(gè)類添加關(guān)聯(lián),并不是直接把這個(gè)值內(nèi)存空間添加到內(nèi)存。
3.5 字典與模型互轉(zhuǎn)
實(shí)現(xiàn)字典和模型之間互相轉(zhuǎn)換。