美文网首页
对runtime做个总结

对runtime做个总结

作者: samtake | 来源:发表于2019-08-12 03:35 被阅读0次

    在iOS动态运行时中,涉及到的有以下几个:

    • 消息传递
    • 方法缓存查找
    • 消息转发
    • 方法混淆(Method-Swizzling)
    • 动态添加方法
    • 动态方法解析
    • 应用场景
    • 学习链接

    消息传递

    消息传递流程.png

    这个过程中涉及到的函数

    id objc_msgSend ( id self, SEL op, ... );
    void objc_msgSendSuper ( struct objec_super *super, SEL op, ... );
    

    像:[self class]、[super class]无论他们最终被哪个对象调用,最后的接收者都是当前对象。

    方法缓存查找

    • 在search_method_list函数中,会去判断当前methodList是否有序,如果有序,会调用findMethodInSortedMethodList方法,这个方法里面的实现是一个二分搜索。如果非有序,就调用线性的傻瓜式遍历搜索。
    • 如果父类找到NSObject还没有找到,那么就会开始尝试_class_resolveMethod方法。
    • _class_resolveMethod这个函数首先判断是否是meta-class类,如果不是元类,就执行_class_resolveInstanceMethod,如果是元类,执行_class_resolveClassMethod。这里有一个lookUpImpOrNil的函数调用。
    • 如果lookUpImpOrNil返回nil,就代表在父类中的缓存中找到,于是需要再调用一次_class_resolveInstanceMethod方法。保证给sel添加上了对应的IMP。
    • 在lookUpImpOrForward方法中,如果也没有找到IMP的实现,那么method resolver也没用了,只能进入消息转发阶段。进入这个阶段之前,imp变成_objc_msgForward_impcache。最后再加入缓存中。

    消息转发

    2019-08-12 02:24:21.425776+0800 runtime-learning[46126:1176084] resolveInstanceMethod:
    2019-08-12 02:24:21.425942+0800 runtime-learning[46126:1176084] forwardingTargetForSelector:
    2019-08-12 02:24:21.426039+0800 runtime-learning[46126:1176084] methodSignatureForSelector:
    2019-08-12 02:24:21.426164+0800 runtime-learning[46126:1176084] forwardInvocation:
    

    方法混淆(Method-Swizzling)

    +(void)load{
        Method test = class_getClassMethod(self, @selector(test));
        Method otherTest = class_getClassMethod(self, @selector(otherTest));
        
        method_exchangeImplementations(test, otherTest);
    }
    

    一般用于了解用户行为以及分析线上问题而进行的埋点:对页面进入次数、页面停留时间、点击事件的埋点。

    动态添加方法

    demo里没有test方法的实现,通过class_addMethod添加它的实现:

    void testIMP (void){
        NSLog(@"testIMP invoke");
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
        if (sel == @selector(test)) {
            
            NSLog(@"resolveInstanceMethod:");
            
            
            //动态添加test方法的实现
            class_addMethod(self, @selector(test), testIMP, "v@:");
            
            return NO;
        }
        return [super resolveInstanceMethod:sel];
    }
    
    2019-08-12 03:17:26.040536+0800 runtime-learning[46921:1198653] resolveInstanceMethod:
    2019-08-12 03:17:26.040895+0800 runtime-learning[46921:1198653] testIMP invoke
    

    动态方法解析

    @dynamic 声明的属性,get方法set方法都是在运行时添加,而不是在编译器声明具体的实现。

    应用场景

    主要学一下某些框架里的实际应用场景
    

    学习链接

    文中的一些demo

    runtime官方API https://developer.apple.com/documentation/objectivec/objective-c_runtime?preferredLanguage=occ

    GitHub上的runtime 源码

    德志 (@halfrost 的三篇关于runtime的文章
    objc_runtime_isa_classobjc_runtime_objc_msgsendhow_to_use_runtime

    相关文章

      网友评论

          本文标题:对runtime做个总结

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