iOS Runtime03 - 消息转发流程

901 阅读2分钟

1.前沿

接上一遍,方法的慢速与快速方法查找流程,都没有找到方法,这时候将会进入方法动态决议流程。源码如:

if (slowpath(behavior & LOOKUP_RESOLVER)) {

//^= 逻辑异或

behavior ^= LOOKUP_RESOLVER;

return resolveMethod_locked(inst, sel, cls, behavior);

}

以上方法为何会执行多次呢?,带着这个问题探索如下:

2.探索动态决议resolveMethod_locked方法

下层源码: 1.判断对象的类是否存在,存在调用 resolveInstanceMethod,并且在这个方法中进行容错处理。之后在查询方法。源码如图 因此,系统会在这之后发送一次消息,也让动态方法决议的作用,在给一次查询的机会。

2.类方法动态决议,执行resolveInstanceMethodelse条件。步骤同对象方法一样。 假如为了不让找不到的方法,造成程序不崩溃,可以用如下方法解决: 步骤1: 在类方法的动态决议中为什么也需要拯救一次呢? 因为类方法在元类中是以对象方法的形式存在的。重点类的继承链图

步骤2:新建一个NSObject+(LQ)分类文件

并且实现如图的方法: // 调用方法的时候 - 分类

+ (BOOL)resolveInstanceMethod:(SEL)sel{
    NSLog(@"%@ 来了",NSStringFromSelector(sel));
    if (sel == @selector(say666)) {
        NSLog(@"%@ 来了",NSStringFromSelector(sel));

        IMP imp           = class_getMethodImplementation(self, @selector(sayMaster));
        Method sayMMethod = class_getInstanceMethod(self, @selector(sayMaster));
        const char *type  = method_getTypeEncoding(sayMMethod);
        return class_addMethod(self, sel, imp, type);
    }
    else if (sel == @selector(sayNB)) {
        
        IMP imp           = class_getMethodImplementation(objc_getMetaClass("LGPerson"), @selector(lgClassMethod));
        Method sayMMethod = class_getInstanceMethod(objc_getMetaClass("LGPerson"), @selector(lgClassMethod));
        const char *type  = method_getTypeEncoding(sayMMethod);
        return class_addMethod(objc_getMetaClass("LGPerson"), sel, imp, type);
    }
    return NO;
}

注意,此方法不是最好的解决问题的方法

3、本文重点消息转发探索

当动态决议完成后,系统做了啥?

结束后,系统:进入此log_and_fill_cache方法中。重点是查看logMessageSend 在logMessageSend方法中能生成信息文件-> command+shift+g //输入/tmp/msgSends/,运行工程 结果如下 验证步骤:

1)步骤1.在相应的类中实现

//快速转发流程

- (id)forwardingTargetForSelector:(SEL)aSelector{
    
    NSLog(@"快速转发:%s == %@",__func__, NSStringFromSelector(aSelector));
//    return [super forwardingTargetForSelector:aSelector];
    //找个存在的方法做事情
//    return [LGStudent alloc];
    //runtime +aSelector + addMethod + imp,只需要返回对象
//    return self;
    
    return [super forwardingTargetForSelector:aSelector];
}

结果如图: 如何补救呢? 步骤1:定义好补救的类,如图方式,方可补救 结论:当动态决议之后,通过消息快速转发,

若是找到补救方法,则消息处理,程序棒棒的。

如是没找到,或者返回nil,进入下一步步骤2

2.)步骤2:慢速转发。

实现methodSignatureForSelector,返回消息的签名NSMethodSignature

搭配一个方法的使用- (void)forwardInvocation:(NSInvocation *)anInvocation 完整的如下:

,总结,通过以上步骤的探索,消息转发流程如下: