美文网首页
Runtime底层原理分析

Runtime底层原理分析

作者: 85ca4232089b | 来源:发表于2020-03-24 16:25 被阅读0次

    Runtime是一套API,有两个版本的:
    一个是legacy Version版本。早期版本Objective-C 1.0 32位的Mac OSX的平台
    一个是Modern Version版本。现行版本iPhone程序和Mac OS X V10.5以后的64系统

    Objective-C程序有三种途径和运行时系统交互

    1. 通过 Objective-C源代码
    2. 通过Foundation框架中的 NSObject的方法
    3. 通过调用运行时系统提供给我们的API接口

    对象方法和类方法

       Person *p = [[Person alloc] init];
       [p run];
    

    clang 分析
    终端命令 clang -rewrite-objc main.m -o main.cpp

    typedef struct objc_object Person;
    typedef struct {} _objc_exc_Person;
    
    int main(int argc, const char * argv[]) {
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
            Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
            ((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));
    // (void (*)(id, SEL))(void *)objc_msgSend)((id)p。  消息的接受者
    // sel_registerName("run")   方法编号 
        }
        return 0;
    }
    

    Person编译成一个objc_object的结构体,OC对象的本质就是一个结构体
    任何的方法调用的本质都是: 都会编译成objc_msgSend方法
    • 对象方法发送消息

       objc_msgSend(p,sel_registerName("run"));
       NSLog(@"%p---%p",sel_registerName("run"),@selector(run));
    // 0x7fff356b2cc2---0x7fff356b2cc2
    

    • 类方法发送消息

       objc_msgSend(objc_getClass("LGStudent"),sel_registerName("walk"));
    

    • 向父类发送消息(对象方法)

        struct objc_super cus;
        cus.receiver = p;
        cus.super_class = class_getSuperclass([p class]);
        objc_msgSendSuper(&cus, @selector(run));
    

    • 向父类发送消息(类方法)

        struct objc_super cusSuper;
        cusSuper.receiver = [p class ];
        cusSuper.super_class = class_getSuperclass(objc_getClass([p class]));
        objc_msgSendSuper(&cusSuper, @selector(run));
    

    objc_getClass([p class]):代表元类

    1. 对象方法是存在类上的
    2. 类方法是存在元类上的
    3. 对象和类分在在类和元类上都是以实例存在的,所以对象当发和实例方法都是以实例方法的形式存在的

    消息查找&转发

    汇编部分

    • objc_msgSend
    • LNilOrTagged tagged pointer 存储一些简单数据:NSNumber NSDadte 如果指针小于等于 LNilOrTagged 直接return返回
    • LGetLsaDone isa 处理完毕
    • CacheLookup 是个宏定义 NORMAL 缓存查找imp
      • call imp
      • objc_msgSend_uncached
      • CacheHit -> CALL
      • CheckMiss ->__objc_msgSend_uncached
       • 1 GETIMP-> LGetImpMiss
       • 2 NORMAL->__objc_msgSend_uncached->_class_lookupMethodAndLoadCache3 C函数
       • 3 LOOKUP->__objc_msgLookup_uncached
      • add
    • MethodTableLookup
    • bl __class_lookupMethodAndLoadCache3


    runtime-汇编.png

    消息查找&转发部分

    动态方法解析

    No implementation found. Try method resolver once.只会执行一次
    • 对象方法 _class_resolveInstanceMethod
    • 类方法 _class_resolveClassMethod

    void _class_resolveMethod(Class cls, SEL sel, id inst)
    {
        if (! cls->isMetaClass()) {//不是元类
            // try [cls resolveInstanceMethod:sel]
            _class_resolveInstanceMethod(cls, sel, inst);
        } 
        else {//是元类
            // try [nonMetaClass resolveClassMethod:sel]
            // and [cls resolveInstanceMethod:sel]
            _class_resolveClassMethod(cls, sel, inst);
            if (!lookUpImpOrNil(cls, sel, inst, 
                                NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) 
            {
                _class_resolveInstanceMethod(cls, sel, inst);
            }
        }
    }
    

    当我们实现这个方法的时候

    + (BOOL)resolveInstanceMethod:(SEL)sel{
        NSLog(@"hellow");
    return [super resolveInstanceMethod:sel];
    }
    
    动态方法解析.png

    其实执行了两次,为什么呢


    动态方法解析调用.png
    static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst){
        BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
        bool resolved = msg(cls, SEL_resolveInstanceMethod, sel);
    }
    

    因为系统默认发送了一次消息:给当前类发送一个SEL_resolveInstanceMethod的消息.
    另外说明一点:

     Method hellowordM1= class_getClassMethod(self, hellowordSEL);
    Method hellowordM= class_getInstanceMethod(object_getClass(self), hellowordSEL);
    

    • 类方法是存在元类上的
    • 对象方法是存在类上面的
    • 都是以实力对象的方式存在的
    • 类的类方法和元类的对象方法是一样的

    标准消息转发流程

    _objc_msgForward_impcache
    通过源码可以发现只有汇编的调用没有实现,但是我们可以通过instrumentObjcMessageSends 输出系统函数的调用

    extern void instrumentObjcMessageSends(BOOL);
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            instrumentObjcMessageSends(YES);
            [LGPerson  walk];
            instrumentObjcMessageSends(NO);
        }
        return 0;
    }
    

    运行之后可以发现在‎⁨Macintosh HD⁩ ▸ ⁨private⁩ ▸ ⁨tmp⁩路径下面会发现一个msgSends-54285的文件


    消息转发的流程查看.png

    从这里可以发现消息转发的流程:
    • resolveInstanceMethod
    • forwardingTargetForSelector
    • methodSignatureForSelector
    • forwardInvocation
    • doesNotRecognizeSelector
    实际的应用场景:
    • 自定义事件处理。crash的手机 调用的堆栈信息,保存沙盒,上传服务器
    • aop切面变成。aspect
    • 数组越界的处理
    • 消息转发..
    • 运行时动态创建一些控制器等等,需要隐藏的页面

    demo

    相关文章

      网友评论

          本文标题:Runtime底层原理分析

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