美文网首页
ios OC方法调用流程(如何避免找不到方法而崩溃)

ios OC方法调用流程(如何避免找不到方法而崩溃)

作者: liang1030 | 来源:发表于2020-07-13 15:11 被阅读0次

    OC中方法调用本质就是objc_msgSend(id target, selector)函数的调用,如果是对象方法,那么这个target是类对象;如果是类方法,则这个target是元类对象。

    一,查找方法调用流程

    1,按照方法名去cache_t中查找方法,找到了就直接调用。
    2,1中未找到,进入类对象方法列表中查找。这个列表包含了分类的方法。
    3,如果在方法列表中找到了方法,则首先将方法加入cache_t中,然后调用方法。
    4,如果在方法列表中未找到方法,会通过superclass找到父类,在父类中进行1、2、3步骤。
    5,如果最终未找到方法,会进入方法的动态解析阶段。

    二,未找到可执行的方法

    objc_msgSend ()函数调用的执行分3个阶段:

    1,找到方法,消息发送。
    2,方法未找到,进入动态解析流程。
    3,态解析流程未处理,进入消息转发流程。

    如果这3个阶段都没有处理方法调用,则会奔溃unrecognized selector send to instance...。

    动态方法解析流程:

    当runtime系统在Cache和类的方法列表(包括父类)中找不到要执行的方法时runtime会调用resolveInstanceMethod: 或者resolveClassMethod: 来给我们一次动态添加方法实现的机会。

    1,会根据是对象方法还是类方法调用类方法resolveInstanceMethod :(SEL)sel与resolveClassMethod :(SEL)sel。
    2,可以在上述方法里面动态添加方法sel的实现,这样就会调用到方法。
    3,态添加的方法,先添加在类的方法列表中,之后再走的查找方法的流程,在找到方法调用之前会将方法加入到方法缓存列表cache_t中,再执行方法。
    4,如果这里没有动态添加方法实现,但是返回值是YES, 就会进入消息转发阶段。

    我们需要用class_addMethod函数完成向特定类添加特定方法实现的操作:

    - (void)test_aaaaaa{
        NSLog(@"test_aaaaaa");
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel{
       
        if (sel == @selector(test)) {
            
            Method method2 = class_getInstanceMethod(self, @selector(test_aaaaaa));
            class_addMethod(self, sel, method_getImplementation(method2), method_getTypeEncoding(method2));
            // 这里class_addMethod()中第一个参数self是类对象
            // 如果是类方法,则class_addMethod()调用时,第一个参数应该写元类对象object_getClass(self)
            return YES;
        }
        
        return [super resolveInstanceMethod:sel];
    }
    + (BOOL)resolveClassMethod:(SEL)sel{
        return [super resolveClassMethod:sel];
    }
    

    参考链接:
    https://www.jianshu.com/p/e54a6a96765d
    https://www.jianshu.com/p/3d3eea1ea00c

    相关文章

      网友评论

          本文标题:ios OC方法调用流程(如何避免找不到方法而崩溃)

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