Runtime 学习笔记

2017-06-30  本文已影响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

南峰子系列文章

上一篇下一篇

猜你喜欢

热点阅读