从慢速查找过程的角度分析Runtime消息调用流程
2023-09-06 21:01:50
前言
在前一篇文章中,我们通过分析方法的本质,了解了objc_msgSend
函数的一个快速缓存查找过程。如果在进行快速查找时,无法找到IMP,查找过程并不会结束,而是会开始另一个过程——慢速查找过程。
慢速查找过程
慢速查找过程是在快速查找过程失败后进行的。它通过以下步骤来查找IMP:
- 首先,它会检查类是否实现了
forwardInvocation:
方法。如果实现了,它会调用该方法。 - 如果没有实现
forwardInvocation:
方法,它会检查类是否实现了methodSignatureForSelector:
方法。如果实现了,它会调用该方法来获取方法签名。 - 如果没有实现
methodSignatureForSelector:
方法,它会检查类是否实现了respondsToSelector:
方法。如果实现了,它会调用该方法来检查类是否响应选择器。 - 如果没有实现
respondsToSelector:
方法,它会检查类是否实现了doesNotRecognizeSelector:
方法。如果实现了,它会调用该方法来通知类它不认识选择器。 - 如果没有实现
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的掌握程度。