返回

OC底层探究之Method慢速查找流程详解

IOS

前言

《OC底层探究之从cache到objc_msgSend》 文章中,我们对 OC 运行时中方法调用的汇编快速查找流程进行了分析。本文将深入探究在快速查找流程失败后的慢速查找流程,进一步揭开 OC 底层方法调用的奥秘。

汇编慢速查找流程

当汇编快速查找流程(cache查找)失败时,系统将进入慢速查找流程,该流程主要包括以下几个步骤:

  1. 消息发送者检查: 检查消息发送者的类是否实现了所调用的方法。
  2. 父类查找: 如果消息发送者的类没有实现该方法,则向上查找父类是否实现了该方法。
  3. 元类查找: 如果父类查找也失败,则检查消息发送者的元类是否实现了该方法。
  4. 协议查找: 如果元类查找也失败,则遍历消息发送者实现的所有协议,检查这些协议是否实现了该方法。
  5. 动态方法解析: 如果所有查找都失败,则调用动态方法解析(resolveInstanceMethod:resolveClassMethod:)方法,尝试动态生成该方法。

慢速查找流程的汇编实现

慢速查找流程的汇编实现位于 objc-runtime-new.h 头文件中,主要包括以下几个汇编函数:

  • objc_msgSend_uncached:未缓存的消息发送函数,用于触发慢速查找流程。
  • objc_msgSend_lookup:查找方法的函数,负责执行慢速查找流程中的查找步骤。
  • objc_msgSend_imp:执行方法的函数,在慢速查找流程成功找到方法后调用。

慢速查找流程的 C 语言实现

为了方便理解,我们将慢速查找流程的汇编实现转换为 C 语言,如下所示:

IMP objc_msgSend_uncached(id self, SEL op, ...) {
    va_list args;
    va_start(args, op);
    IMP imp = objc_msgSend_lookup(self, op);
    if (imp == NULL) {
        // 动态方法解析
        // ...
    }
    return imp;
}

IMP objc_msgSend_lookup(id self, SEL op) {
    Class cls = object_getClass(self);
    IMP imp = method_lookup(cls, op);
    if (imp == NULL) {
        // 父类查找
        // ...
        // 元类查找
        // ...
        // 协议查找
        // ...
    }
    return imp;
}

慢速查找流程示例

下面是一个慢速查找流程的示例:

@interface MyClass : NSObject
@end

@implementation MyClass
- (void)myMethod {
    NSLog(@"myMethod called");
}
@end

int main() {
    MyClass *myObject = [[MyClass alloc] init];
    [myObject performSelector:@selector(myMethod)]; // 调用 myMethod 方法
    return 0;
}

在该示例中,当调用 [myObject performSelector:@selector(myMethod)] 时,系统会执行以下步骤:

  1. 快速查找流程失败,触发慢速查找流程。
  2. 慢速查找流程检查 MyClass 类是否实现了 myMethod 方法,发现已实现。
  3. 查找成功,调用 myMethod 方法,输出 "myMethod called"

结语

本文详细分析了 OC 底层方法调用的慢速查找流程,从汇编和 C 语言两个层面进行了阐述。通过理解慢速查找流程,我们可以更深入地掌握 OC 运行时的工作原理。