1、Runtime是什么?
Runtime是一套API,有C C++ 匯編寫成,為OC語言加入了面向?qū)ο蠛瓦\(yùn)行時(shí)功能。
運(yùn)行時(shí)(Runtime)是指將數(shù)據(jù)類型的確定由編譯時(shí)推遲到了運(yùn)行時(shí)。(例如extension-category的區(qū)別)。
平時(shí)寫的OC代碼,在運(yùn)行時(shí)會(huì)被轉(zhuǎn)換成Runtime的C語言代碼,Runtime是OC的幕后工作者。
2、方法的本質(zhì)?SEL是什么?IMP是什么?兩者之間的關(guān)系又是什么?
方法的本質(zhì)是發(fā)送消息,發(fā)送消息會(huì)有以下幾個(gè)流程。
- 快速查找:
(objc_msgSend)~cache_t緩存消息。 - 慢速查找:遞歸自己和父類~
lookUpImpOrForward。 - 查找不到消息:動(dòng)態(tài)方法解析~
resolveInstanceMethod。 - 消息快速轉(zhuǎn)發(fā):
forwardingTargetForSelector。 - 慢速消息轉(zhuǎn)發(fā):
methodSignatureForSelector&forwardInvocation。 - 拋出異常:
doesNotRecognizeSelector。
SEL是方法編號(hào),在read_images時(shí)期就已經(jīng)編譯進(jìn)內(nèi)存。IMP是我們的函數(shù)實(shí)現(xiàn)指針。找IMP就是找函數(shù)的過程。
SEL就相當(dāng)于是我們書本目錄的標(biāo)題。
IMP就相當(dāng)于是我們書本目錄標(biāo)題對(duì)應(yīng)的頁碼。
3、能否向編譯后的得到的類中增加實(shí)例變量?能否向運(yùn)行時(shí)創(chuàng)建的類中增加實(shí)例變量?
- 不能向編譯后的類中增加實(shí)例變量,因?yàn)橐坏┚幾g完成,類中的內(nèi)存結(jié)構(gòu)就已經(jīng)確定,編譯后的實(shí)例變量存儲(chǔ)的
ro中,我們無法修改。 - 只要還沒有注冊(cè)到內(nèi)存中,就可以添加。
- 可以在運(yùn)行時(shí)添加屬性和方法。
4、self&super
@implementation LGPerson
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
我們通過clang將這段代碼轉(zhuǎn)換成C++。
static instancetype _I_LGPerson_init(LGPerson * self, SEL _cmd) {
self = ((LGPerson *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("LGPerson"))}, sel_registerName("init"));
if (self) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dq_m1fkwntx6rsbzm4157sqxsnc0000gn_T_LGPerson_8ad7e9_mi_0, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"))));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dq_m1fkwntx6rsbzm4157sqxsnc0000gn_T_LGPerson_8ad7e9_mi_1, NSStringFromClass(((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("LGPerson"))}, sel_registerName("class"))));
}
return self;
}
精簡代碼后
NSStringFromClass(objc_msgSend((id)self, sel_registerName("class")));
NSStringFromClass(objc_msgSendSuper({(id)self, (id)class_getSuperclass(objc_getClass("LGPerson"))}, sel_registerName("class"))));
我們發(fā)現(xiàn)super關(guān)鍵字底層調(diào)用的是objc_msgSendSuper。
* id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
*
* struct objc_super {
* id receiver;
* Class cls; // the class to search
* }
我們發(fā)現(xiàn)objc_super結(jié)構(gòu)體的第一個(gè)成員變量receiver也就是我們的消息接受者。對(duì)比上面轉(zhuǎn)換后的代碼我們可以發(fā)現(xiàn)receiver的值傳入的是self,也就是說我們當(dāng)前的消息接受者就是我們當(dāng)前的對(duì)象,只不過它是從父類的消息列表中開始查找函數(shù)的實(shí)現(xiàn)。最后交由self去處理。
所以上面的兩次輸出都是LGPerson。