- 动态方法解析阶段
- 当向一个对象发送它不存在的方法消息时,首先进入动态方法解析阶段。
- 运行时系统会调用类方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
(对于实例方法调用) 或 + (BOOL)resolveClassMethod:(SEL)sel
(对于类方法调用)。
- 在这个类方法中,开发者可以通过
class_addMethod
函数动态地向类中添加一个实现该方法的函数。例如:
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(nonExistentMethod)) {
IMP imp = imp_implementationWithBlock(^(id self, NSString* param) {
NSLog(@"动态添加的方法实现,参数: %@", param);
});
class_addMethod(self, sel, imp, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
- 备用接收者阶段
- 如果在动态方法解析阶段没有添加方法实现(即上述类方法返回
NO
),那么进入备用接收者阶段。
- 运行时系统会调用对象的
- (id)forwardingTargetForSelector:(SEL)aSelector
方法。
- 开发者可以在这个实例方法中返回一个能处理该
SEL
的备用对象。如果返回 nil
,则继续下一步。例如:
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(nonExistentMethod)) {
return self.alternateObject; // 假设 alternateObject 能处理该方法
}
return nil;
}
- 完整的消息转发阶段
- 如果备用接收者阶段也没有找到合适的处理对象(即
forwardingTargetForSelector:
返回 nil
),则进入完整的消息转发阶段。
- 运行时系统首先调用
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
方法,开发者需要在这个方法中返回一个合适的 NSMethodSignature
对象,描述不存在方法的参数和返回值类型。如果返回 nil
,则会调用 - (void)doesNotRecognizeSelector:(SEL)aSelector
并抛出异常。例如:
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(nonExistentMethod)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"]; // 假设有一个 NSString 参数的 void 方法
}
return [super methodSignatureForSelector:aSelector];
}
- 接着,运行时系统调用 `- (void)forwardInvocation:(NSInvocation *)anInvocation` 方法,开发者在这个方法中可以将消息转发给其他对象,或者手动实现该方法的功能。例如:
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = anInvocation.selector;
if ([self.alternateObject respondsToSelector:sel]) {
[anInvocation invokeWithTarget:self.alternateObject];
} else {
[super forwardInvocation:anInvocation];
}
}
- 如果 `methodSignatureForSelector:` 返回 `nil`,则最终会调用 `- (void)doesNotRecognizeSelector:(SEL)aSelector`,默认实现会抛出 `NSInvalidArgumentException` 异常,提示该对象无法识别这个选择器。