返回

探索底层方法慢速查找的奥秘:msgSend 底层(二)

IOS

引言

在前一篇文章中,我们揭秘了 Objective-C 消息发送快速查找的机制,了解了缓存命中时的快如闪电的性能。然而,当缓存无功而返时,Runtime 又会如何巧妙地进行慢速查找呢?本篇文章将带你深入探索 __objc_msgSend_uncached,领略慢速查找的奥妙。

慢速查找的起点:__objc_msgSend_uncached

当缓存中找不到相应的方法实现时,Runtime 会调用 __objc_msgSend_uncached 进行慢速查找。这是一个通用函数,负责处理所有找不到缓存的方法调用。

查找方法实现

__objc_msgSend_uncached 会从以下几个方面查找方法实现:

  1. 类方法查找: 首先,它会检查目标对象的类是否实现了该方法。如果实现了,则直接返回该方法实现。
  2. 元类方法查找: 如果目标对象的类中没有找到该方法,则会检查其元类(即该类的类)是否实现了该方法。如果实现了,则返回该方法实现。
  3. 协议方法查找: 如果目标对象的类和元类都没有实现该方法,则会检查该对象是否遵守了任何协议,并在这些协议中查找该方法实现。如果在协议中找到了实现,则返回该实现。
  4. 父类方法查找: 如果在类、元类和协议中都找不到该方法,则会递归地在目标对象的父类中进行查找,直到找到该方法实现或到达根类为止。

动态方法解析

在以上查找步骤中,如果在目标对象所属的类、元类、协议或父类中都没有找到该方法实现,则会触发动态方法解析。动态方法解析允许在运行时动态创建和添加方法实现。

具体来说,Runtime 会调用 +resolveInstanceMethod: 和 +resolveClassMethod: 方法,分别用于动态解析实例方法和类方法。如果这些方法成功解析了方法实现,则将该实现添加到目标对象的类或元类中,并返回该实现。

兜底处理

如果经过上述所有查找步骤,仍然找不到该方法实现,则 Runtime 会调用 __objc_msgSend_uncached 的兜底处理代码。这个兜底处理代码会抛出一个 NSInvalidArgumentException 异常,提示该方法不存在。

结语

通过探索 __objc_msgSend_uncached 的工作原理,我们深入了解了 Objective-C 消息发送的慢速查找机制。从查找方法实现到动态方法解析,再到兜底处理,Runtime 以一种高效、灵活的方式处理了找不到缓存的方法调用,确保了 Objective-C 消息发送机制的健壮性。