返回
在 Objc 消息转发流程中探究 imp 查找不到的情况
IOS
2023-10-10 08:25:42
大家好,欢迎来到本文。今天,我们将深入探讨 Objective-C 消息转发流程中 imp 查找不到的情况,进一步了解 Objective-C 动态方法解析的复杂性。
在上一篇文章《objc_msgSend 消息转发流程探究一》中,我们了解到消息转发流程的第一步是查找类的缓存,以找到对应选择子的 IMP 指针。然而,有时可能会发生找不到 IMP 的情况,从而触发消息转发的后续步骤。
查找不到 IMP 的原因
当 objc_msgSend 找不到 IMP 时,可能有几个原因:
- 类没有实现该方法: 这是最常见的原因。如果一个类没有实现某个特定的方法,则其缓存中不会有相应的 IMP。
- 方法被声明为私有或受保护: 如果一个方法被声明为私有或受保护,则只能在类及其子类中访问。如果一个外部对象尝试调用私有或受保护的方法,则会触发 imp 查找失败。
- 缓存已过期: 在某些情况下,类的缓存可能已过期,并且不包含方法的最新 IMP。这通常发生在方法已被添加到类或从类中删除之后。
- 类的元类不正确: 如果一个类的元类不正确,它可能导致缓存中没有正确的 IMP。这可能发生在元类被错误地设置或修改之后。
imp 查找不到时的处理
当 objc_msgSend 找不到 IMP 时,它将触发消息转发的后续步骤。这些步骤包括:
- 发送
methodSignatureForSelector:
消息: 此消息发送给目标对象,以获取方法的签名。 - 转发消息到
forwardInvocation:
方法: 如果目标对象实现了forwardInvocation:
方法,则将消息转发给该方法。 - 转发消息到
forwardingTargetForSelector:
方法: 如果目标对象没有实现forwardInvocation:
方法,则将消息转发给forwardingTargetForSelector:
方法返回的对象。 - 抛出
NSInvalidArgumentException
异常: 如果上述步骤都失败,则 objc_msgSend 将抛出一个NSInvalidArgumentException
异常。
举个例子
让我们举一个例子来说明 imp 查找不到时的消息转发过程:
@interface MyObject : NSObject
@end
@implementation MyObject
- (void)someMethod {
// ...
}
@end
int main() {
MyObject *obj = [[MyObject alloc] init];
[obj performSelector:@selector(unknownMethod)];
return 0;
}
在这种情况下,unknownMethod
方法没有在 MyObject
类中实现。因此,当 objc_msgSend
尝试查找 IMP 时,它将失败并触发消息转发流程。最终,它会抛出一个 NSInvalidArgumentException
异常,因为 MyObject
类没有实现 forwardInvocation:
或 forwardingTargetForSelector:
方法。
总结
在 Objective-C 消息转发流程中,imp 查找不到是一个常见的情况。当这种情况发生时,会触发一系列后续步骤,包括发送方法签名、转发消息到 forwardInvocation:
方法,以及在所有其他方法都失败时抛出异常。通过理解 imp 查找不到的原因和处理方式,我们可以更深入地了解 Objective-C 动态方法解析的机制。
我希望这篇文章对您了解 Objective-C 消息转发流程有所帮助。如果您有任何疑问或意见,请随时发表评论。谢谢阅读!