Message forwarding mechanism (消息转发机制)

iOS的消息转发机制

iOS的消息转发机制是在消息发送给对象时,找不到对应的实例方法的情况下启动的。消息转发允许对象在运行时处理无法识别的消息,提供了一种动态的、灵活的消息处理方式。

消息转发机制主要分为三个阶段:

  1. 动态方法解析
  2. 快速转发
  3. 标准转发

1. 动态方法解析

在这个阶段,运行时系统会询问对象是否能动态添加方法来处理未知消息。可以通过实现 +resolveInstanceMethod: 或 +resolveClassMethod: 方法来动态添加方法实现。

objc 复制代码
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(someMethod)) {
        class_addMethod([self class], sel, (IMP)someMethodImplementation, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

void someMethodImplementation(id self, SEL _cmd) {
    NSLog(@"Dynamically added method");
}

2. 快速转发

如果动态方法解析失败,运行时会调用 -forwardingTargetForSelector: 方法,询问对象是否有其他对象可以处理该消息。通过返回另一个对象的实例,消息可以转发给该实例。

objc 复制代码
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(someMethod)) {
        return alternateObject;
    }
    return [super forwardingTargetForSelector:aSelector];
}

3. 标准转发

如果前两个阶段都失败,运行时会调用 -methodSignatureForSelector: 和 -forwardInvocation: 方法进行标准消息转发。首先,通过 -methodSignatureForSelector: 方法获取方法签名,然后在 -forwardInvocation: 方法中处理消息。

objc 复制代码
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(someMethod)) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([alternateObject respondsToSelector:[anInvocation selector]]) {
        [anInvocation invokeWithTarget:alternateObject];
    } else {
        [super forwardInvocation:anInvocation];
    }
}

图示

为了更好地理解这个过程,下面是一个示意图:

plaintext 复制代码
+----------------------+
|        Sender        |
+----------------------+
            |
            | Message: someMethod
            v
+----------------------+
|     Receiver         |
+----------------------+
|                      |
| -resolveInstanceMethod:
|     - Can add method? ----> YES (add method)
|                      |
|                      v
|  NO                  |
|                      |
| -forwardingTargetForSelector:
|     - Other object to handle? ----> YES (forward to other object)
|                      |
|                      v
|  NO                  |
|                      |
| -methodSignatureForSelector:
|     - Get method signature ----> Signature or nil
|                      |
|                      v
|  Signature           |
|                      |
| -forwardInvocation:
|     - Handle invocation ----> Forward or error
+----------------------+

示例代码

下面是一个完整的示例代码,展示如何使用消息转发机制:

objc 复制代码
#import <objc/runtime.h>

@interface SQIAlternateObject : NSObject
- (void)someMethod;
@end

@implementation SQIAlternateObject
- (void)someMethod {
    NSLog(@"AlternateObject handling someMethod");
}
@end

@interface MyObject : NSObject
@end

@implementation MyObject {
    SQIAlternateObject *alternateObject;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        alternateObject = [[SQIAlternateObject alloc] init];
    }
    return self;
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(someMethod)) {
        class_addMethod([self class], sel, (IMP)someMethodImplementation, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

void someMethodImplementation(id self, SEL _cmd) {
    NSLog(@"Dynamically added method");
}

- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(someMethod)) {
        return alternateObject;
    }
    return [super forwardingTargetForSelector:aSelector];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(someMethod)) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([alternateObject respondsToSelector:[anInvocation selector]]) {
        [anInvocation invokeWithTarget:alternateObject];
    } else {
        [super forwardInvocation:anInvocation];
    }
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MyObject *obj = [[MyObject alloc] init];
        [obj someMethod];
    }
    return 0;
}

在这个示例中,我们展示了如何通过动态方法解析、快速转发和标准转发来处理 someMethod 方法。

相关推荐
2501_9151063217 小时前
跨平台抓包工具怎么选?TraceEagle抓包鹰 的四种跨平台能力
网络协议·计算机网络·网络安全·ios·adb·https·udp
黑科技iOS上架20 小时前
iOS应用上架:提前规避审核被拒风险
ios·审核
茶底世界之下1 天前
方图一定要裁照片吗?用 Awaking 比较裁切与留白
ios
00后程序员张1 天前
无需 Mac 的 iOS App 上架工具,开心上架Appuploader 负责哪些环节
android·ios·小程序·https·uni-app·iphone·webview
2501_915106321 天前
Windows 用 KXBuild 开发 iOS 项目,CocoaPods、SPM 怎么处理?
windows·vscode·ios·个人开发·swift·敏捷流程·cocoapods
2501_915909061 天前
KXApp 能打开哪些 iOS 项目?xcodeproj 与 CocoaPods 支持清单
ide·vscode·ios·个人开发·xcode·敏捷流程·cocoapods
开心就好20252 天前
uni-app 本地打包 iOS,在 Windows 上使用 KXBuild 产出 ipa 并上架的完整流程
后端·ios
调试人生的显微镜2 天前
跨平台抓包工具怎么选?TraceEagle抓包鹰 的四种跨平台能力
后端·ios
2501_915909062 天前
Ipa Guard 防护上架,混淆、重签名和回归测试怎么做
android·ios·小程序·https·uni-app·iphone·webview
木头分享2 天前
2026淘宝、京东双11活动全自动脚本丨IOS+安卓
ios