runtime+消息转发
2020-07-23 本文已影响0人
如果大雨落下
首先通过isa去类对象,查找方法,找不到就一层层往父类上找,如果最后还找不到,就走消息转发
- resolveInstanceMethod,
如果在类对象上找不到方法,源码解释
// No implementation found. Try method resolver once.
if (slowpath(behavior & LOOKUP_RESOLVER)) {
behavior ^= LOOKUP_RESOLVER;
return resolveMethod_locked(inst, sel, cls, behavior);
}
在这个resolveInstanceMethod可以动态的去添加方法,BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, sel); 等于是执行了resolveInstanceMethod方法,并且获取里面的返回值,然后再去获取方法,如果里面动态添加了方法,就阔以执行了,如果没有,就走转发??
/***********************************************************************
* resolveInstanceMethod
* Call +resolveInstanceMethod, looking for a method to be added to class cls.
* cls may be a metaclass or a non-meta class.
* Does not check if the method already exists.
**********************************************************************/
**********************************************************************/
static void resolveInstanceMethod(id inst, SEL sel, Class cls)
{
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
SEL resolve_sel = @selector(resolveInstanceMethod:);
if (!lookUpImpOrNil(cls, resolve_sel, cls->ISA())) {
// Resolver not implemented.
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveInstanceMethod adds to self a.k.a. cls
IMP imp = lookUpImpOrNil(inst, sel, cls);
if (resolved && PrintResolving) {
if (imp) {
_objc_inform("RESOLVE: method %c[%s %s] "
"dynamically resolved to %p",
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel), imp);
}
else {
// Method resolver didn't add anything?
_objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES"
", but no new implementation of %c[%s %s] was found",
cls->nameForLogging(), sel_getName(sel),
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel));
}
}
}
通过runtime ,动态的将没有的方法的实现指向另外一个方法的实现
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(test)) {
Method method = class_getInstanceMethod(self, @selector(otherMethod));
IMP imp = method_getImplementation(method);
class_addMethod(self, sel, imp, method_copyReturnType(method));
}
return YES;
}
增加C语言方法
C语言里面方法名就是对应的函数指针,IMP的实现
"v16@0:8" v代表返回值是void,16 代表参数占16个字节,@代表第一个参数是id类型,0代表第一个参数从0个字节开始,:代表第二个参数,8代表第二个参数从第8个字节开始
类方法需要添加到元类对象,获取元类对象:object_getClass(self)
void cotherTest(id self,SEL sel)
{
printf("test00000");
NSLog(@"%@ ----%@",self,NSStringFromSelector(sel));
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(test)) {
class_addMethod(self, sel, (IMP)cotherTest, "v16@0:8");
}
return YES;
}
+ (BOOL)resolveClassMethod:(SEL)sel
{
if (sel == @selector(test)) {
class_addMethod(object_getClass(self), sel, (IMP)cotherTest, "v16@0:8");
}
return YES;
}
以上均为方法解析阶段,如果在方法解析阶段,并没有顺利的进行方法的调用
进入消息转发阶段
- (id)forwardingTargetForSelector:(SEL)aSelector
{
NSLog(@"herhe--%@",NSStringFromSelector(aSelector));
return [[Cat alloc] init];;
}
这里可以返回一个新的对象来接收并执行这个方法,获取到对象后,在通过objc_sengdMsg(新的对象,aselector),即可以进行新对应方法的调用
如果并没有进行消息的转发,那会进入方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSLog(@"herhe111--%@",NSStringFromSelector(aSelector));
return return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"]; //v16@0:8 返回值和参数
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
}
这里可以将aSelector ,生成一个方法签名,并返回,然后在通过forwardInvocation 去实现调用
在forwardInvocation 里面可以执行任何想执行的东西,不写任何东西,也不会走到 unrecognized selector sent to instance
类方法同样也可以走这一套流程,只不过相应的方法需要换成 + (),即类方法,直接输入没有联想,修改即可,因为源码里面是直接通过对象指针调用的这个方法,如果用的类对象,则直接调用的是元类的类方法,所以直接将实例方法改为类方法,即可实现



