美文网首页
Runtime 学习笔记

Runtime 学习笔记

作者: 黄花菜先生 | 来源:发表于2017-06-30 17:09 被阅读18次

    要点一:对象,类,元类关系

    image.png

    每个对象都有一个类对象

    每个类对象有一个元类对象

    每一个对象都有一个isa指针,这个指针指向它的类对象

    每一个类对象都有一个isa指针和一个super_class指针,isa指针指向它的元类对象,super_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;  // 类的版本信息,默认为0
        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;
    

    1.类对象:类对象存储的是关于实例对象的信息(属性,实例方法等)

    2.元类对象:元类对象存储的是关于类的信息(类的版本,名字,类方法等)

    3.类对象(class object)和元类对象(metaclass object)的定义都是objc_class结构

    4.根类NSObject的类对象没有父类,根元类继承于类对象,根元类的isa指向自己.

    5.所有类的类对象的继承关系就是元类对象的继承关系。

    要点三:方法调用会被缓存

    调用的方法会被缓存。

    一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。

    要点四:分类的动态插入

    typedef struct category_t {
        const char *name;  //类的名字
        classref_t cls; //类
        struct method_list_t *instanceMethods;  //category中所有给类添加的实例方法的列表
        struct method_list_t *classMethods; //category中所有添加的类方法的列表
        struct protocol_list_t *protocols; //category实现的所有协议的列表
        struct property_list_t *instanceProperties; //category中添加的所有属性
    } category_t;
    

    从category的定义也可以看出category的可为(可以添加实例方法,类方法,甚至可以实现协议,添加属性)和不可为(无法添加实例变量)。

    假如有一个名称为test的实例方法,实例方法在对象的类对象实例方法列表中,当我们调用[self test]这个方法时,会先去该对象的类对象的实例方法列表中去找,如果没找到,继续去类对象的父类中去找。

    类对象的实例方法是在编译的时候添加到方法列表中的,分类的实例方法是在运行时动态添加到类对象的方法列表中的,[self test] 找实例方法的时候是按顺序查找的,因为分类的实例方法是后来添加的,所以肯定在方法列表的前面,所以就先调用分类的方法。

    两个分类有相同的实例方法的时候,就看动态添加的时候,是谁后添加到方法列表中的了,谁后添加,谁就在前面,就调用谁。

    要点五:OC函数不能像C++一样被重载

    因为OC是根据方法名称生成的SEL来查找方法的实现imp的,如果再方法列表中有两个名称一样的方法,那么对象将无法分辨到底现在调用的是那个方法,相同的方法只能对应一个SEL。

    参考资料

    刨根问底Objective-C Runtime系列

    runtime源码

    深入理解Objective-C:Category

    南峰子系列文章

    相关文章

      网友评论

          本文标题:Runtime 学习笔记

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