Runtime是什么
將一些在編譯、鏈接過程中的工作,放到運(yùn)行階段声登,因此Objective-C
為動(dòng)態(tài)語言
Runtime
是一個(gè)庫格遭,這個(gè)庫使我們可以在程序運(yùn)行時(shí)創(chuàng)建對象哈街、檢查對象、修改類和對象的方法拒迅。
Runtime是怎么工作的
Class和Object
在objc.h
中骚秦,Class
被定義為指向objc_class
的指針她倘,定義如下:
typedef struct objc_class *Class;
而objc_class
是一個(gè)結(jié)構(gòu)體,在runtime.h
中的定義如下:
struct objc_class {
// isa指針指向的類結(jié)構(gòu)稱為metaclass作箍,其中存放著static類型的成員變量與static類型的方法(“+”開頭的方法)
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
// 指向該類的父類的指針硬梁,如果該類是根類(如NSObject或NSProxy),那么super_class就為nil胞得。
Class super_class OBJC2_UNAVAILABLE; // 父類
const char *name OBJC2_UNAVAILABLE; // 類名
long version OBJC2_UNAVAILABLE; // 類的版本信息荧止,可以通過runtime函數(shù)class_setVersion或者class_getVersion進(jìn)行修改、讀取
long info OBJC2_UNAVAILABLE; // 類信息阶剑,供運(yùn)行時(shí)期使用的一些位標(biāo)識跃巡、如CLS_CLASS(0x1L)表示該類為普通 class,其中包含實(shí)例方法和變量牧愁;CLS_META(0x2L)表示該類為metaclass素邪,其中包含類方法;
long instance_size OBJC2_UNAVAILABLE; // 該類的實(shí)例變量大兄戆搿(包括從父類繼承下來的實(shí)例變量)
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變量地址列表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法的地址列表兔朦,與info的一些標(biāo)識位有關(guān),如CLS_CLASS(0x1L)則存儲實(shí)例方法磨确,如CLS_META(0x2L)沽甥,則存儲類方法;
struct objc_cache *cache OBJC2_UNAVAILABLE; // 緩存最近使用的方法列表俐填,用于提升效率
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 存儲該類聲明遵守的協(xié)議
#endif
} OBJC2_UNAVAILABLE;
一個(gè)類包含了自身所有的成員變量(ivars
)安接、所有的方法(methodLists
)、實(shí)現(xiàn)的協(xié)議(protocols
)
isa
的定義如下:
struct objc_object {
// 是一個(gè)指向objc_class結(jié)構(gòu)體的指針
// objc_object(實(shí)例對象)中isa指針指向的類結(jié)構(gòu)稱為class(也就是該對象所屬的類)其中存放著普通成員變量與動(dòng)態(tài)方法(“-”開頭的方法)
Class isa OBJC_ISA_AVAILABILITY;
};
一個(gè)對象唯一保存的信息就是它的Class
的地址
調(diào)用對象方法的實(shí)現(xiàn)過程
- 通過isa去找到對應(yīng)的
objc_class
; - 在
objc_class
的methodLists
中找到我們調(diào)用的方法英融,然后執(zhí)行盏檐。
Meta Class 元類
Objective-C中,類也被設(shè)計(jì)為一個(gè)對象驶悟。
調(diào)用對象類方法的實(shí)現(xiàn)過程(不考慮繼承)
- 通過對象的
isa
指針找到對應(yīng)的類胡野; - 通過類的
isa
指針找到對應(yīng)元類; - 在元類的
methodList
中痕鳍,找到對應(yīng)的方法硫豆,然后執(zhí)行。
Method
定義如下:
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE; // 方法名
char *method_types OBJC2_UNAVAILABLE; // 方法類型
IMP method_imp OBJC2_UNAVAILABLE; // 方法實(shí)現(xiàn)
}
SEL
是一個(gè)指向objc_selector
的指針,而非objc_selector
在頭文件中找不到明確的定義铭若。不過是一個(gè)保存方法名的字符串洪碳。
IMP
函數(shù)指針:找到函數(shù)地址递览,然后執(zhí)行函數(shù)。
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...)
id
對于實(shí)例方法來說瞳腌,self
保存了當(dāng)前對象的地址绞铃;對于類方法來說,self
保存了當(dāng)前對應(yīng)類對象的地址嫂侍;后面的省略號即是參數(shù)列表儿捧。
Method
建立了SEL
和IMP
的關(guān)聯(lián),當(dāng)對一個(gè)對象發(fā)送消息時(shí)吵冒,會通過給出的SEL去找到IMP纯命,然后執(zhí)行。
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
當(dāng)向一個(gè)對象發(fā)送消息時(shí)痹栖,會去這個(gè)類methodLists
中查找對應(yīng)的SEL
亿汞,如果查不到,則通過super_class
指針找到父類揪阿,再去父類的methodLists
中查找疗我,層層遞進(jìn)。最后仍然找不到南捂,才走拋異常流程吴裤。
攔截調(diào)用和消息轉(zhuǎn)發(fā)流程
重寫
resolveClassMethod:
resolveInstanceMethod:
消息發(fā)送
objc_msgSend函數(shù)的調(diào)用過程:
- 第一步:檢測這個(gè)
selector
是不是要忽略的。 - 第二步:檢測這個(gè)
target
是不是nil對象溺健。nil
對象發(fā)送任何一個(gè)消息都會被忽略掉麦牺。 - 第三步:
1.調(diào)用實(shí)例方法時(shí),它會首先在自身isa
指針指向的類(class
)methodLists
中查找該方法鞭缭,如果找不到則會通過class
的super_class
指針找到父類的類對象結(jié)構(gòu)體剖膳,然后從methodLists
中查找該方法,如果仍然找不到岭辣,則繼續(xù)通過super_class
向上一級父類結(jié)構(gòu)體中查找吱晒,直至根class
;
2.當(dāng)我們調(diào)用某個(gè)某個(gè)類方法時(shí)沦童,它會首先通過自己的isa
指針找到metaclass
仑濒,并從其中methodLists
中查找該類方法,如果找不到則會通過metaclass
的super_class
指針找到父類的metaclass
對象結(jié)構(gòu)體偷遗,然后從methodLists
中查找該方法墩瞳,如果仍然找不到,則繼續(xù)通過super_class
向上一級父類結(jié)構(gòu)體中查找氏豌,直至根metaclass
矗烛; - 第四部:前三部都找不到就會進(jìn)入動(dòng)態(tài)方法解析(看下文)。
第一步:通過
resolveInstanceMethod:
方法決定是否動(dòng)態(tài)添加方法箩溃。如果返回Yes則通過class_addMethod
動(dòng)態(tài)添加方法瞭吃,消息得到處理,結(jié)束涣旨;如果返回NO
歪架,則進(jìn)入下一步;第二步:這步會進(jìn)入
forwardingTargetForSelector:
方法霹陡,用于指定備選對象響應(yīng)這個(gè)selector
和蚪,不能指定為self
。如果返回某個(gè)對象則會調(diào)用對象的方法烹棉,結(jié)束攒霹。如果返回nil
,則進(jìn)入第三部浆洗;第三部:這步我們要通過
methodSignatureForSelector:
方法簽名催束,如果返回nil
,則消息無法處理伏社。如果返回methodSignature`抠刺,則進(jìn)入下一步;第四部:這步調(diào)用
forwardInvocation
:方法摘昌,我們可以通過anInvocation
對象做很多處理速妖,比如修改實(shí)現(xiàn)方法,修改響應(yīng)對象等聪黎,如果方法調(diào)用成功罕容,則結(jié)束。如果失敗稿饰,則進(jìn)入doesNotRecognizeSelector
方法锦秒,若我們沒有實(shí)現(xiàn)這個(gè)方法,那么就會crash
湘纵。
Category
struct objc_category {
char *category_name OBJC2_UNAVAILABLE; // 類別名稱
char *class_name OBJC2_UNAVAILABLE; // 類名
struct objc_method_list *instance_methods OBJC2_UNAVAILABLE; // 實(shí)例方法列表
struct objc_method_list *class_methods OBJC2_UNAVAILABLE; // 類方法列表
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協(xié)議列表
}
objc_category
中包含對象方法列表脂崔、類方法列表、協(xié)議列表梧喷。
可以通過關(guān)聯(lián)對象的方式給類別添加可用的屬性
Runtime的常規(guī)操作
-
Method Swizzling
方法交換 - 獲取所有屬性和方法
Runtime的應(yīng)用場景
- AOP面向切面編程(對業(yè)務(wù)邏輯進(jìn)行分離砌左,降低耦合度)
- 字典轉(zhuǎn)模型
- 進(jìn)行歸解檔
- 逆向開發(fā)
- 熱修復(fù)
新手也看得懂的 iOS Runtime 教程
RSSwizzle源碼解析
Objective-C Runtime 1小時(shí)入門教程
深入理解Objective-C:Category