objc_msgSend()實(shí)現(xiàn)
2.動(dòng)態(tài)解析階段:
1. 判斷之前是否動(dòng)態(tài)解析過(guò):
- 沒(méi)解析,進(jìn)入判斷,并在解析完成后秘噪,標(biāo)志位置位YES:
triedResolver = YES
;
if (resolver && !triedResolver) {
runtimeLock.unlockRead();
_class_resolveMethod(cls, sel, inst);
runtimeLock.read();
// Don't cache the result; we don't hold the lock so it may have
// changed already. Re-do the search from scratch instead.
triedResolver = YES;
goto retry;
}
2. 進(jìn)入動(dòng)態(tài)解析:_class_resolveMethod(cls, sel, inst);
- 根據(jù)你這個(gè)類是
類對(duì)象
還是元類對(duì)象
調(diào)用不同的方法: [cls resolveInstanceMethod:sel]
[nonMetaClass resolveClassMethod:sel]
void _class_resolveMethod(Class cls, SEL sel, id inst)
{
if (! cls->isMetaClass()) {
// try [cls resolveInstanceMethod:sel]
_class_resolveInstanceMethod(cls, sel, inst);
}
else {
// try [nonMetaClass resolveClassMethod:sel]
// and [cls resolveInstanceMethod:sel]
_class_resolveClassMethod(cls, sel, inst);
if (!lookUpImpOrNil(cls, sel, inst,
NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
{
_class_resolveInstanceMethod(cls, sel, inst);
}
}
}
如何實(shí)現(xiàn):
舉例: Person類中只有一個(gè)實(shí)例方法 - (void)test;
的聲明;
方法一:
- 直接使用
method
- (void)other {
NSLog(@"%s", __func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(test)) {
// 獲取其他方法
Method method = class_getInstanceMethod(self, @selector(other));
// 動(dòng)態(tài)添加test方法的實(shí)現(xiàn)
class_addMethod(self, sel,
method_getImplementation(method),
method_getTypeEncoding(method));
// 返回YES代表有動(dòng)態(tài)添加方法
return YES;
}
return [super resolveInstanceMethod:sel];
}
方法二:
- 自定義
method_t
:
struct method_t {
SEL sel;
char *types;
IMP imp;
};
- (void)other {
NSLog(@"%s", __func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(test)) {
// 獲取其他方法
struct method_t *method = (struct method_t *)class_getInstanceMethod(self, @selector(other));
// 動(dòng)態(tài)添加test方法的實(shí)現(xiàn)
class_addMethod(self, sel, method->imp, method->types);
// 返回YES代表有動(dòng)態(tài)添加方法
return YES;
}
return [super resolveInstanceMethod:sel];
}
方法三:
- 調(diào)用C語(yǔ)言函數(shù):
void c_other(id self, SEL _cmd) {
NSLog(@"c_other - %@ - %@", self, NSStringFromSelector(_cmd));
}
+ (BOOL) resolveInstanceMethod:(SEL)sel {
if (sel == @selector(test)) {
// 第一個(gè)參數(shù)是object_getClass(self)
class_addMethod(self, sel, (IMP)c_other, "v16@0:8");
return YES;
}
return [super resolveInstanceMethod:sel];
}
如果是調(diào)用類方法:+ (void)test
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(test)) {
//object_getClass(self) 獲取當(dāng)前類
Method methodClass = class_getClassMethod(object_getClass(self), @selector(other));
class_addMethod(object_getClass(self), sel, method_getImplementation(methodClass), method_getTypeEncoding(methodClass));
return YES;
}
return [super resolveClassMethod:sel];
}
動(dòng)態(tài)解析流程圖:
- 先判斷該方法是否進(jìn)行過(guò)動(dòng)態(tài)解析;
- 如果沒(méi)有烫堤,調(diào)用
+ (BOOL) resolveInstanceMethod:(SEL)sel
或+ (BOOL)resolveClassMethod:(SEL)sel
來(lái)進(jìn)行動(dòng)態(tài)方法解析; - 動(dòng)態(tài)方法解析如果有實(shí)現(xiàn):會(huì)有一個(gè)
class_addMethod
函數(shù),將方法添加到類對(duì)象的class_rw_t
的methods
; - 不管動(dòng)態(tài)方法解析階段有沒(méi)有方法實(shí)現(xiàn)鸽斟,是否進(jìn)行過(guò)動(dòng)態(tài)解析標(biāo)志位都會(huì)置為YES:
triedResolver = YES
; - 并再返回第一步消息發(fā)送階段,進(jìn)行方法查找:
goto retry
:- 如果動(dòng)態(tài)解析有方法實(shí)現(xiàn)拔创,方法查找階段就會(huì)在
class_rw_t
的methods
中找到方法; - 如果動(dòng)態(tài)解析方法沒(méi)有實(shí)現(xiàn)富蓄,方法仍舊找不到剩燥;
- 如果動(dòng)態(tài)解析有方法實(shí)現(xiàn)拔创,方法查找階段就會(huì)在
- 進(jìn)入消息轉(zhuǎn)發(fā)階段。