美文网首页
runtime+消息转发

runtime+消息转发

作者: 如果大雨落下 | 来源:发表于2020-07-23 11:35 被阅读0次

首先通过isa去类对象,查找方法,找不到就一层层往父类上找,如果最后还找不到,就走消息转发

  1. 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

类方法同样也可以走这一套流程,只不过相应的方法需要换成 + (),即类方法,直接输入没有联想,修改即可,因为源码里面是直接通过对象指针调用的这个方法,如果用的类对象,则直接调用的是元类的类方法,所以直接将实例方法改为类方法,即可实现

相关文章

  • runtime+消息转发

    首先通过isa去类对象,查找方法,找不到就一层层往父类上找,如果最后还找不到,就走消息转发 resolveInst...

  • Runtime

    相关简单介绍 消息机制消息传递机制消息转发机制-动态添加方法消息转发机制-快速转发消息转发机制-慢速转发消息转发机...

  • 消息转发机制(动态消息转发)

    例子分析 1)在给程序添加消息转发功能以前,必须覆盖两个方法,即methodSignatureForSelecto...

  • Runtime 消息转发

    目录 消息转发背景知识 消息转发使用方式 消息转发常见问题 消息转发背景知识 1.消息转发的定义Objective...

  • 消息转发

    参考:https://www.jianshu.com/p/76ed71216cde

  • 消息转发

    执行一个没有实现的方法,程序会在运行时挂掉并抛出 unrecognized selector sent to … ...

  • 消息转发

    OC中的方法调用,其实都是转化成objc_msgSend函数调用 1.信息发送 2.动态方法解析 /// 对象消息解析

  • 消息转发

    1. 消息查找 Objective-C 具有很强的动态性,它将静态语言在编译和链接时期做的工作,放置到运行时来处理...

  • 消息转发

    一张图说明消息转发 例如我们进行这样一个操作:People这个类并没有实现perfectGotoSchool这个函...

  • 消息转发

网友评论

      本文标题:runtime+消息转发

      本文链接:https://www.haomeiwen.com/subject/xbeclktx.html