美文网首页
浅谈Runtime(一)

浅谈Runtime(一)

作者: 小宇pod | 来源:发表于2018-05-06 17:12 被阅读0次

    如有不同看法,欢迎讨论。

    一. RunTime是什么

    runtime(简称运行时),是一套 纯C(C和汇编写的) 的API。而 OC 就是 运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
    这里要提的一点是,在C中的是无法调用未实现的函数的,否则会报错;但是在OC中,只要声明了方法就可以调用,只有在程序运行的时候才会报错,这一点也反映了OC的动态特性。

    二. 动态特性

    关于OC的动态特性主要体现在以下三个方面:1.动态类型:即运行时再决定对象类型。比如我们常见的id类型,任何对象都可以被id类型的指针所指,在运行时再确定具体类型;2.动态绑定:即在运行时决定该对象所拥有的对象及方法,一个例子就是在编写代码的时候,一个只声明未实现的方法依然可以被调用,但在运行时才会报错;3:动态载入:在运行时决定需要加载哪一部分资源,同样一个常见的例子就是通过不同机型决定加载@2x的图片还是@3x的图片。

    三. Class的结构

    首先是通过终端输入

    clang -rewrite-objc MyClass.m
    
    则会出现一个.cpp的C++编译的文件 WechatIMG20.jpeg

    里边的代码很多,全局搜索

    typedef struct objc_class *Class;
    

    你会看到

    typedef struct objc_class *Class;
    struct objc_object {
        Class isa __attribute__((deprecated));
    };
    

    即Class其实是一个objc_class类型的结构体,而objc_object是一个包含着isa指针的结构体,在runtime.h中我们可以看到objc_class的定义:

    struct objc_class {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    
    #if !__OBJC2__
        Class _Nullable super_class                              OBJC2_UNAVAILABLE;
        const char * _Nonnull name                               OBJC2_UNAVAILABLE;
        long version                                             OBJC2_UNAVAILABLE;
        long info                                                OBJC2_UNAVAILABLE;
        long instance_size                                       OBJC2_UNAVAILABLE;
        struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
        struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
        struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
        struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
    #endif
    } OBJC2_UNAVAILABLE;
    

    其中具体的变量看英文名大体就能明白具体是干什么的,比如objc_method_list就是这个类所包含的方法列表,objc_ivar_list是成员变量列表,等等等等。同样我们也能通过Runtime取到这个类的属性,方法等;或者在运行中给类绑定属性,方法。

    四. 消息发送流程

    在这里我们已经知道,OC是一门动态语言,那么就有一个问题出来了,消息是怎么发送的,换言之当我们调用这个类的方法时发生了什么?
    定义一个MyClass类,然后声明一个方法

    - (void)showName:(NSString *)name;
    

    OC 在向一个对象发送消息时,runtime 库会根据对象的isa指针遍历这个对象的methodLists,如果没找到,会遍历父类的methodLists,最终找到 SEL ,根据 id 和 SEL 确认 IMP(指针函数),在发送消息。如果找不到,则程序崩溃,报常见的unrecognized selector sent to class 0x10bb9b060,即没有找到实现的方法。
    任何方法本质上都是向对象发送消息,比如我们常见的

        MyClass *class = [MyClass alloc];
    

    可以用runtime这样写

    MyClass *class = ((MyClass * (*) (id, SEL)) objc_msgSend) (objc_getClass("MyClass"), sel_registerName("alloc"));
    

    解释一下(id, SEL)是传入参数类型,也就是说,如果需要调用函数是带参数的,需要增加参数个数,例如:

    int str = ((int (*) (id, SEL, int)) objc_msgSend) (objc_getClass("MyClass"), sel_registerName("showInt:"),12);
    

    MyClass * ()是返回的类型,如果方法无返回值则是void ()。
    先写到这里,至于Runtime的具体应用和应用场景再开一篇再写。

    相关文章

      网友评论

          本文标题:浅谈Runtime(一)

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