美文网首页
21期_iOS_方法转发流程分析

21期_iOS_方法转发流程分析

作者: 萧修 | 来源:发表于2023-08-22 01:05 被阅读0次

    本文通过分析消息的动态决议,快速转发,慢速转发三个节阶段,完善objc_messend最后流程

    -、消息转发:
    、动态解析方法resolveinstanceMethod。动态方法解析,class_addMethod()
    、如果上面,方法添加没有执行,那么执行消息接受者重定向。【forwardingTargetForSelector】
    、如果上面返回nil,就会调用方法签名获取函数的参数和返回值类型,同时调用forwardinvocation通知当前对象。

    动态方法决议

    对象方法的决议

    static void resolveInstanceMethod(id inst, SEL sel, Class cls)
    {
        SEL resolve_sel = @selector(resolveInstanceMethod:);
    
        //1、检查resolveInstanceMethod的imp是否为空,如果为空,直接返回。nsobject默认实现了,这里主要是检查子类是否实现
        if (!lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA(/*authenticated*/true))) {
            // Resolver not implemented.
            return;
        }
        
        //2、重新定义objc_msgSend
        BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
        //第三个参数`sel`为resolveInstanceMethod的参数,然后发送resolveInstanceMethod消息
        bool resolved = msg(cls, resolve_sel, sel);
        
        //3、经过resolveInstanceMethod的处理,可能已经动态添加imp,所以再次获取sel的imp是否存在,如果存在结束转发,否则继续转发
        IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
    }
    

    类方法的决议的处理流程和对象方法类似。

    • 实例代码
    + (BOOL)resolveInstanceMethod:(SEL)sel {
        //未实现的方法判断
        if (sel == @selector(speak)) {
            Method method = class_getInstanceMethod(self, sel);
            const char *types = method_getTypeEncoding(method);
            IMP imp = class_getMethodImplementation(self, sel);
            return class_addMethod(self, sel, imp, types);
        }
        return [super resolveInstanceMethod:sel];
    }
    

    forwardingTargetForSelector

    此方法可以直接返回一个对象来接受消息。

    实例源码

    //交由另外对象处理本条消息
    - (id)forwardingTargetForSelector:(SEL)aSelector {
        if (aSelector == @selector(speak)) {
            //
            return [GGXPerson2 alloc];
        }
        return [super forwardingTargetForSelector:aSelector];
    }
    
    另一个类
    @implementation GGXPerson2
    - (void)speak {
        NSLog(@"快速转发forwardingTartgetForSelector");
    }
    @end
    

    消息慢速转发

    methodsignatureForSelector

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
       if (aSelector == @selector(speak)) {
            return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        }
        return [super methodSignatureForSelector:aSelector];
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
       SEL aSelector = [anInvocation selector];
       if ([[GGXPerson2 alloc] respondsToSelector:aSelector])
           [anInvocation invokeWithTarget:[GGXPerson2 alloc]];
       else
           [super forwardInvocation:anInvocation];
    }
    

    问题汇总

    • 可以使用动态决议处理崩溃问题,但是需要对方法名过滤
    • forwordingtarget转发的对象也未实现,消息转发会在此类进行,进行resovle->forwarding->等方法
    • forwarding和methodsingnature,后面会再次执行消息决议是因为,进行了签名,在内部调用栈中,需要判断class_respondsToSelector对签名认证。内部调用lookUpImpOrNilTryCache

    总的来看:消息转发进入步骤为动态方法决议,快速转发,慢速转发三者按照顺序,成功处理就不进入下个流程

    相关文章

      网友评论

          本文标题:21期_iOS_方法转发流程分析

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