返回

imp 慢速查找_ObjC 底层原理(08)

IOS

在上一篇文章 底层原理(07) 中,分析了方法的快速查找流程即缓存查找,如果缓存中没有找到就会。。。下面就会进入方法慢速查找流程。。。

一. __objc_msgSend_uncached

在当前类中,

- (void)sayHi;

生成一个 _objc_msgSend_uncached 消息。进入 __objc_msgSend_uncached 的流程:

// 如果缓存查找结果是 null,就会进入这个流程,开始慢速查找。
objc_method_t objc_msgSend_uncached(id self, SEL op, ...) {
  // setup a call frame to try finding the message
  struct objc_super super;

  // 因为类的元类是类,对象也存在自己的元类,所以需要一个结构体来存储父类和对象类对应的类。
  super.receiver = (id)self;
  super.class = object_getClass((id)self);

  // sender 指向方法调用者,就是当前的对象。
  void *sender = &super;

  // 找到这个类的方法,如果方法不存在,返回 null,我们再从超类开始找。
  objc_method_t result = _objc_msg_lookup_method((id)self, op, sender);

  // 既然进入了慢速查找,那么肯定找不到对应的缓存,首先从当前类开始查找方法。
  // 调用 _objc_msg_lookup_method() 函数,返回方法结构体。
  // 因为这个方法没有缓存,所以我们必须调用查找方法的方法来得到它的方法结构体。
  if (result) {
    // 若当前类有这个方法,那么就是调用了 - (void)sayHi 这个方法,根据前面章节的知识,调用
    // _objc_msgSend_cached 就实现了消息的发送。

    // 查找到了方法,那么缓存起来。
    _cache_method(self, op, result, sender);
  } else {
    // 如果在当前类没有找到,则继续向上递归寻找。
    result = _objc_msg_lookup_super(super.receiver, op, &super.class);

    // 这里继续向父类查找方法,如果父类中存在这个方法,那么就返回对应的方法结构体。
    // 如果父类不存在这个方法,返回 null,继续在父类的父类中查找。
    if (result) {
      // 如果有父类调用父类中的方法,这种方法就是 override,然后缓存起来。
      _cache_method(self, op, result, sender);
    }
  }

  return result;
}

二. 查找步骤

如果缓存查找失败,那么就需要使用慢速查找的方法 __objc_msgSend_uncached 来查找方法。

这个函数会尝试从当前类及其超类中查找指定的方法。如果找到,则会将其缓存起来,以加快下次查找的速度。

  1. 调用 __objc_msg_lookup_method 函数在当前类中查找方法。
  2. 如果在当前类中没有找到,则继续向上递归寻找。
  3. 如果在任何超类中都找不到,则返回 null。

三. 使用 __objc_msgSend_uncached 方法

- (void)sayHi;

生成一个 _objc_msgSend_uncached 消息。进入 __objc_msgSend_uncached 的流程,查找方法并缓存起来,然后调用 _objc_msgSend_cached 函数发送消息。

- (void)sayHi;
{
  id self, _cmd;
  // 发送消息
  __objc_msgSend_uncached(self, _cmd);
}