返回

从慢速查找过程的角度分析Runtime消息调用流程

IOS

前言

在前一篇文章中,我们通过分析方法的本质,了解了objc_msgSend函数的一个快速缓存查找过程。如果在进行快速查找时,无法找到IMP,查找过程并不会结束,而是会开始另一个过程——慢速查找过程。

慢速查找过程

慢速查找过程是在快速查找过程失败后进行的。它通过以下步骤来查找IMP:

  1. 首先,它会检查类是否实现了forwardInvocation:方法。如果实现了,它会调用该方法。
  2. 如果没有实现forwardInvocation:方法,它会检查类是否实现了methodSignatureForSelector:方法。如果实现了,它会调用该方法来获取方法签名。
  3. 如果没有实现methodSignatureForSelector:方法,它会检查类是否实现了respondsToSelector:方法。如果实现了,它会调用该方法来检查类是否响应选择器。
  4. 如果没有实现respondsToSelector:方法,它会检查类是否实现了doesNotRecognizeSelector:方法。如果实现了,它会调用该方法来通知类它不认识选择器。
  5. 如果没有实现doesNotRecognizeSelector:方法,它会引发一个异常。

消息发送和慢速查找过程之间的关系

消息发送过程和慢速查找过程是紧密相关的。当消息发送过程失败时,它会调用慢速查找过程来查找IMP。慢速查找过程成功找到IMP后,它会将IMP存储在快速查找缓存中,以便下次消息发送时可以使用。

示例代码

// 定义一个类
@interface MyClass : NSObject

// 实现forwardInvocation:方法
- (void)forwardInvocation:(NSInvocation *)invocation;

// 实现methodSignatureForSelector:方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector;

// 实现respondsToSelector:方法
- (BOOL)respondsToSelector:(SEL)selector;

// 实现doesNotRecognizeSelector:方法
- (void)doesNotRecognizeSelector:(SEL)selector;

@end

// 实现MyClass类
@implementation MyClass

// 实现forwardInvocation:方法
- (void)forwardInvocation:(NSInvocation *)invocation {
    // 获取选择器
    SEL selector = [invocation selector];

    // 检查类是否实现了选择器
    if ([self respondsToSelector:selector]) {
        // 调用选择器
        [invocation invokeWithTarget:self];
    } else {
        // 调用doesNotRecognizeSelector:方法
        [self doesNotRecognizeSelector:selector];
    }
}

// 实现methodSignatureForSelector:方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
    // 获取方法签名
    NSMethodSignature *methodSignature = [super methodSignatureForSelector:selector];

    // 检查方法签名是否为空
    if (methodSignature == nil) {
        // 调用doesNotRecognizeSelector:方法
        [self doesNotRecognizeSelector:selector];
    }

    // 返回方法签名
    return methodSignature;
}

// 实现respondsToSelector:方法
- (BOOL)respondsToSelector:(SEL)selector {
    // 检查类是否实现了选择器
    BOOL respondsToSelector = [super respondsToSelector:selector];

    // 返回是否实现了选择器
    return respondsToSelector;
}

// 实现doesNotRecognizeSelector:方法
- (void)doesNotRecognizeSelector:(SEL)selector {
    // 抛出异常
    [NSException raise:NSInvalidArgumentException format:@"unrecognized selector: %@", NSStringFromSelector(selector)];
}

@end

// 创建MyClass类的实例
MyClass *myClass = [[MyClass alloc] init];

// 调用MyClass类的实例方法
[myClass performSelector:@selector(myMethod)];

运行结果

unrecognized selector: myMethod

在上面的示例代码中,我们定义了一个名为MyClass的类,并实现了forwardInvocation:methodSignatureForSelector:respondsToSelector:doesNotRecognizeSelector:方法。我们还创建了一个MyClass类的实例,并调用了它的实例方法myMethod。由于MyClass类没有实现myMethod方法,因此会调用慢速查找过程。慢速查找过程会检查类是否实现了forwardInvocation:methodSignatureForSelector:respondsToSelector:方法。由于MyClass类实现了这些方法,因此慢速查找过程会成功找到IMP。但是,由于MyClass类没有实现doesNotRecognizeSelector:方法,因此会抛出一个异常。

结论

慢速查找过程是消息发送过程的重要组成部分。它可以帮助我们找到没有在快速查找缓存中找到的IMP。通过理解慢速查找过程,我们可以更深入地理解Objective-C中的消息机制,提高对Runtime的掌握程度。