返回

Runtime(三)方法缓存

IOS

1. 方法缓存

1.1 为什么会有方法缓存

在了解类的基本结构之后,本文开始了解探讨 iOS 中的消息发送,即消息调用。首先开始讨论的是——在真正消息调用之前,我们会去方法缓存里面寻找真实的函数地址,iOS 提供的缓存机制用于提高效率。

1.2 方法缓存是什么

方法缓存本质上是一个哈希表,用来存储已经被解析过的selector 和 IMP 的对应关系,存储在 objc_selrefs 中,key 是selector,value 是 IMP(函数指针)。

1.3 方法缓存的存储结构

方法缓存的存储结构为:

struct objc_selrefs {
    unsigned int count;
    unsigned int size;
    SEL *refs;
    IMP *imp;
};
  • count:已缓存的方法数量。
  • size:缓存的大小。
  • refs:指向已缓存的 selector 的指针数组。
  • imp:指向已缓存的 IMP 的指针数组。

1.4 方法缓存的查找过程

当我们发送消息的时候,首先会去方法缓存里面寻找真实的函数地址,如果找到,则直接调用这个函数地址;如果没有找到,则会去类方法列表里面寻找,如果找到,则把这个函数地址缓存到方法缓存里面,然后调用这个函数地址;如果在类方法列表里面也没有找到,则会去父类的方法列表里面寻找,以此类推,直到找到为止。

2. 方法查找

2.1 方法查找的流程

方法查找的流程如下:

  1. 在方法缓存里面寻找真实的函数地址。
  2. 如果在方法缓存里面没有找到,则会去类方法列表里面寻找。
  3. 如果在类方法列表里面也没有找到,则会去父类的方法列表里面寻找,以此类推,直到找到为止。

2.2 方法查找的优化

为了提高方法查找的效率,iOS 提供了一些优化措施:

  • 方法缓存 :方法缓存是一个哈希表,用来存储已经被解析过的 selector 和 IMP 的对应关系,存储在 objc_selrefs 中,key 是 selector,value 是 IMP(函数指针)。
  • 类方法列表 :类方法列表是一个数组,用来存储类中的所有方法,存储在 class_ro_t 结构体中,可以通过 class_getMethodList() 函数获取。
  • 父类的方法列表 :父类的方法列表是一个数组,用来存储父类中的所有方法,存储在 class_ro_t 结构体中,可以通过 class_getSuperclass() 函数获取父类,然后通过 class_getMethodList() 函数获取父类的方法列表。

3. 总结

方法缓存是一种提高消息发送效率的机制,它可以减少方法查找的时间。方法查找的流程是:首先在方法缓存里面寻找真实的函数地址,如果找到,则直接调用这个函数地址;如果没有找到,则会去类方法列表里面寻找,如果找到,则把这个函数地址缓存到方法缓存里面,然后调用这个函数地址;如果在类方法列表里面也没有找到,则会去父类的方法列表里面寻找,以此类推,直到找到为止。为了提高方法查找的效率,iOS 提供了一些优化措施,包括方法缓存、类方法列表和父类的方法列表。