美文网首页
Runtime学习笔记

Runtime学习笔记

作者: HoooChan | 来源:发表于2019-01-28 20:12 被阅读7次

    对象模型

    新建一个类:

    #import <Foundation/Foundation.h>
    
    @interface CustomClass : NSObject
    
    @end
    
    @implementation CustomClass
    
    @end
    
    int main(int argc, char * argv[]) {
        CustomClass *customObject = [[CustomClass alloc] init];
    }
    

    在终端运行以下命令:

    xcrun -sdk iphonesimulator12.0 clang -rewrite-objc CustomObject.m

    .m文件被编译成C++文件,截取部分代码如下:

    ...
    typedef struct objc_object CustomClass;
    ...
    int main(int argc, char * argv[]) {
        CustomClass *customObject = ((CustomClass *(*)(id, SEL))(void *)objc_msgSend)((id)((CustomClass *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("CustomClass"), sel_registerName("alloc")), sel_registerName("init"));
    }
    ...
    

    可以看到我们定义的CustomClass被定义成objc_object结构体,在main函数里面的CustomClass *customObject其实就是struct objc_object *customObject,所以customObject的本质就是一个指向objc_object结构体的指针。

    objc_object的源码:

    struct objc_object {
        Class isa  OBJC_ISA_AVAILABILITY;
    };
    

    可以看到objc_object有一个Class类型的isa变量,这个isa是指向该实例所属的类的。而Class其实本质就是objc_class

    typedef struct objc_class *Class;
    

    objc_class的源码:

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

    类其实也是对象,它的isa指向的类就是这个类的元类(meta-class)。元类只有一个对象,就是类对象。类方法就在类对象里面。

    给一个对象发送消息,会到这个对象所属的类里面找对应的方法;给一个类发送消息,会到这个类的元类(也就是类对象所属的类)里面去找对应的方法。

    而元类也是类,它也有isa指针,这个isa指针统一都直接指向NSObject的元类。而NSObject的元类的isa则指向自己。另外NSObject的元类的父类则指向NSObject。而其他子类的元类指向其父类的元类。

    objc_class除了isa和super_class之外,还有objc_ivar_listobjc_method_list分布保存属性和方法。

    objc_method_list其实就是objc_method的列表。

    objc_method的源码:

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

    SEL的定义:

    typedef objc_selector * SEL;
    

    可以理解为区分方法的 ID。

    在Object-C中可以通过以下方法获得SEL:

    SEL @selector(<selector)
    
    SEL sel_registerName(const char * _Nonnull str)
    

    IMP的定义:

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

    指向最终实现程序的内存地址的指针。

    消息机制

    在Object-C里的函数调用其实都是发送消息,[receiver massage]会被编译成

    objc_msgSend(receiver, selector)
    

    如果有参数,则为:

    objc_msgSend(receiver, selector, arg1, arg2, ...)
    

    objc_class 里面还有一个变量:struct objc_cache *cache,它主要是为了调用的性能进行优化的。每当实例对象接收到一个消息时,它会先到cache中去找能够响应的方法,找不到再去方法列表里面找。找到之后就会保存到cache里面。已备下次再被调用。

    如果对象接收到无法解读的消息,那将会调用其所属类的以下类方法:

    + (BOOL)resolveInstanceMethod:(SEL)sel
    

    sel就是那个未知的选择子,返回的BOOL类型来表示这个类能否新增一个实例方法来处理这个选择子。所以本类有机会新增一个处理此选择子的方法。一般是在resolveInstanceMethod:方法里面调用class_addMethod方法来动态添加方法,但前提是实现代码已经提前写好了。

    如果上述方法返回的是NO,那么当前接受者还有第二次机会,runtime还会调用该对象的以下方法,看能否将该消息转发给其他接受者处理:

    - (id)forwardingTargetForSelector:(SEL)aSelector
    

    如果此时还是返回nil,那么会来到完整的消息转发。runtime会调用以下方法:

     - (void)forwardInvocation:(NSInvocation *)anInvocation
    

    anInvocation包含了那条尚未处理的消息的全部细节,包括选择子、目标以及参数。这个步骤可以修改消息的内容,比如追加参数或者改变选择子等。如果本类不处理此消息,会调用超类的同名方法。最后传到NSObject时会调用“doesNotRecognizeSelector:”抛出异常。

    Category原理

    KVO原理

    参考

    相关文章

      网友评论

          本文标题:Runtime学习笔记

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