RunTime

作者: 愤怒的八哥 | 来源:发表于2019-02-13 23:22 被阅读14次

    运行时系统负责完成
    1、对象的生成、释放时的内存管理。
    2、为发来的消息查找对应的处理方法。
    OC的消息是在运行时才去绑定,运行时系统首先会确认接收者的类型(动态类型识别),然后根据消息名称在类的方法列表中查找,如果没找到就到父类中继续查找,假如一直找到NSObject都没有找到要调用的方法,进入消息转发,最后会报告不能识别上述消息的错误。
    三种不同的层级上与 Runtime 系统进行交互
    1、通过 Objective-C 源代码
    2、通过 Foundation 框架的NSObject类定义的方法
    3、通过对 runtime 函数的直接调用。

    消息发送的过程详解

    OC消息源码会被编译成
    id objc_msgSend ( id self, SEL op, ... );
    id

    /// A pointer to an instance of a class.
    typedef struct objc_object *id;
    /// Represents an instance of a class.
    struct objc_object {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    };
    

    Class

    typedef struct objc_class *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;
    
    class-diagram.jpg
    上图实线是 superclass 指针,虚线是isa指针。 有趣的是根元类的超类是 NSObject,而 isa 指向了自己,而 NSObject 的超类为 nil,也就是它没有超类。
    SEL
    objc_msgSend函数第二个参数类型为SEL,它是selector在Objc中的表示类型(Swift中是Selector类)。selector是方法选择器,可以理解为区分方法的 ID,而这个 ID 的数据结构是SEL:
    typedef struct objc_selector *SEL;
    

    其实它就是个映射到方法的C字符串

    **objc_method **

    struct objc_method {
        SEL _Nonnull method_name                                 OBJC2_UNAVAILABLE;
        char * _Nullable method_types                            OBJC2_UNAVAILABLE;
        IMP _Nonnull method_imp                                  OBJC2_UNAVAILABLE;
    }                                                            OBJC2_UNAVAILABLE;
    

    objc_ivar

    struct objc_ivar {
        char * _Nullable ivar_name                               OBJC2_UNAVAILABLE;
        char * _Nullable ivar_type                               OBJC2_UNAVAILABLE;
        int ivar_offset                                          OBJC2_UNAVAILABLE;
    #ifdef __LP64__
        int space                                                OBJC2_UNAVAILABLE;
    #endif
    }     
    
    struct objc_category {
        char * _Nonnull category_name                            OBJC2_UNAVAILABLE;
        char * _Nonnull class_name                               OBJC2_UNAVAILABLE;
        struct objc_method_list * _Nullable instance_methods     OBJC2_UNAVAILABLE;
        struct objc_method_list * _Nullable class_methods        OBJC2_UNAVAILABLE;
        struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
    }                                                            OBJC2_UNAVAILABLE;
    
    

    class_copyIvarList 函数获取的不仅有实例变量,还有属性。但会在原本的属性名前加上一个下划线。
    对比下 class_copyIvarList 函数,使用 class_copyPropertyList 函数只能获取类的属性,而不包含成员变量。但此时获取的属性名是不带下划线的。
    IMP

    typedef void (*IMP)(void /* id, SEL, ... */ );
    

    注意点
    1、当 self 为实例对象时,[self class] 与 object_getClass(self) 等价,因为前者会调用后者。object_getClass([self class]) 得到元类。
    2、当 self 为类对象时,[self class] 返回值为自身,还是 self。object_getClass(self) 与 object_getClass([self class]) 等价。

    常用方法

    1、关联,Runtime系统让Objc支持向对象动态添加变量。涉及到的函数有以下三个:

    void objc_setAssociatedObject ( id object, const void *key, id value, objc_AssociationPolicy policy );
    id objc_getAssociatedObject ( id object, const void *key );
    void objc_removeAssociatedObjects ( id object );
    

    2、方法交换,Aspect库实现了 方法前中后加入代码,替换原方法。

    + (void)load {
        SEL originalSelector = @selector(ReceiveMessage:);
        SEL overrideSelector = @selector(replacementReceiveMessage:);
        Method originalMethod = class_getInstanceMethod(self, originalSelector);
        Method overrideMethod = class_getInstanceMethod(self, overrideSelector);
        if (class_addMethod(self, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
                class_replaceMethod(self, overrideSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
                method_exchangeImplementations(originalMethod, overrideMethod);
        }
    }
    

    3、路由跳转,动态生成对象,给对象赋值。
    4、获取成员变量列表快速归档
    参考:
    http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/

    相关文章

      网友评论

        本文标题:RunTime

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