返回

iOS底层探索篇——Runtime-objc_msgSend流程分析 - 慢速查找流程(下)

IOS

objc_msgSend 流程中的慢速查找:深入解析消息传递的底层机制

慢速查找:当快速查找失败时

在 iOS 开发中,objc_msgSend 函数是对象间通信和消息传递的核心。在前一篇文章中,我们探讨了 objc_msgSend 的快速查找流程,这是一个高效的过程,可以在对象本身内快速找到方法实现。然而,当快速查找失败时,objc_msgSend 会进入慢速查找流程。让我们深入研究一下这个过程。

向上查找继承链

慢速查找流程涉及在对象的继承链中逐级向上查找实现方法。当在当前对象中找不到方法时,objc_msgSend 会调用 class_getInstanceMethod() 函数在父类中查找方法。如果在父类中找到了方法,就会使用 method_getImplementation() 函数获取实现的地址。

接下来,objc_msgSend 使用 imp() 函数将实现地址转换为函数指针,然后调用此函数指针执行方法实现。如果在父类中找不到方法,则会继续向上查找父类的父类,直到找到实现为止。

代码示例:慢速查找流程

// 当前对象未实现方法
NSObject *obj = [[NSObject alloc] init];
[obj performSelector:@selector(methodNotFound)];

// class_getInstanceMethod() 在父类中查找方法
Method method = class_getInstanceMethod([obj class], @selector(methodNotFound));

// method_getImplementation() 获取实现地址
IMP implementation = method_getImplementation(method);

// imp() 转换为函数指针
void (*func)(id, SEL) = (void *)implementation;

// 调用函数指针执行方法
func(obj, @selector(methodNotFound));

转发机制:灵活的消息处理

如果在所有父类中都找不到方法实现,objc_msgSend 将返回 NULL。此时,可以使用转发机制将消息转发给其他对象。转发机制有两种类型:消息转发和方法转发。

消息转发:重定向消息

消息转发允许您将消息转发到不同的对象。这可以通过实现 forwardingTargetForSelector() 方法来实现。在此方法中,您可以返回要转发消息的目标对象。objc_msgSend 随后会将消息转发到返回的对象。

方法转发:委托方法实现

方法转发允许您将方法实现转发到不同的对象。这可以通过实现 forwardInvocation() 方法来实现。在此方法中,您可以实现方法的转发。objc_msgSend 随后会将方法实现转发到 forwardInvocation() 方法。

代码示例:消息转发

// 实现 forwardingTargetForSelector()
@implementation NSObject (MessageForwarding)

- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (@selector(methodNotFound) == aSelector) {
        return [[OtherObject alloc] init];
    }
    return nil;
}

@end

// 使用消息转发
NSObject *obj = [[NSObject alloc] init];
[obj performSelector:@selector(methodNotFound)]; // 消息转发到 OtherObject

结论:消息传递的强大性

objc_msgSend 的慢速查找流程和转发机制是理解消息传递机制的关键部分。它们允许您在对象层次结构中有效地查找和执行方法,并在需要时灵活地重定向消息。通过掌握这些概念,您可以编写更强大、更可扩展的 iOS 应用程序。

常见问题解答

  1. 什么时候使用慢速查找流程?

    • 当快速查找流程无法在对象本身中找到方法实现时。
  2. 转发机制有什么好处?

    • 允许更灵活的消息处理,例如将消息或方法实现委托给不同的对象。
  3. 如何实现消息转发?

    • 通过实现 forwardingTargetForSelector() 方法。
  4. 如何实现方法转发?

    • 通过实现 forwardInvocation() 方法。
  5. objc_msgSend 的慢速查找流程比快速查找流程慢多少?

    • 慢速查找流程涉及额外的查找步骤,因此比快速查找流程慢。