三大阶段:1. 消息发送 2. 动态方法解析 3. 消息转发
消息发送

- 从receiverClass的class_rw_t中查找方法
- 已经排好序的方法列表,使用二分查找
- 没有排序的方法列表,使用遍历查找
- receiver通过isa找到receiverClass
- receiverClass通过superClass指针找到superClass
动态方法解析
![]()
void c_errorMethod(id self, SEL _cmd) { NSLog(@"%s", __func__); } - (void)errorMethod { NSLog(@"%s", __func__); } // 动态方法解析 - 实例对象方法 + (BOOL)resolveInstanceMethod:(SEL)sel { if (sel == @selector(method)) { Method errorMethod = class_getInstanceMethod(self, @selector(errorMethod)); IMP errorImp = method_getImplementation(errorMethod); const char *type = method_getTypeEncoding(errorMethod); class_addMethod(self, sel, errorImp, type); return YES; } return [super resolveInstanceMethod:sel]; } // 动态方法解析 - 类方法 + (BOOL)resolveClassMethod:(SEL)sel { if (sel == @selector(method)) { // 获取元类对象 Class metaClass = object_getClass(self); // c_errorMethod的编码为"v@:" // 规则:v表示返回值void,@表示第1个参数是对象类型,:表示第2个参数是SEL类型 // 完整规则参考TypeEncoding官方文档 const char *type = "v@:"; class_addMethod(metaClass, sel, (IMP)c_errorMethod, type); return YES; } return [super resolveClassMethod:sel]; }
如果已经进行过动态方法解析,依然没有处理该消息,则会进入消息转发阶段
消息转发
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(method)) {
// 如果返回了一个新的对象,则会触发objc_msgSend(aNewObj, aSelector)
return aNewObj;
}
return [super forwardingTargetForSelector:aSelector];
}
// 如果forwardingTargetForSelector:没有返回一个合适的对象
// 那么就会触发methodSignatureForSelector:方法
// 返回一个NSInvocation对象给forwardInvocation:.
// 通过子类重写该方法,将消息转发给其他对象
// NSInvocation对象使用来自methodSignatureForSelector:返回的信息创建
/*
anInvocation.target;//消息接收对象
anInvocation.selector;//方法名
[anInvocation getReturnValue:];//返回值
[anInvocation getArgument: atIndex:];// 参数
*/
- (void)forwardInvocation:(NSInvocation *)anInvocation {
}
// 如果返回值为nil,则不会触发forwardInvocation:
// 而会去直接触发doesNotRecognizeSelector:抛出异常
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(method)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
//备注: doesNotRecognizeSelector:方法可以重写,但不能正常返回
//(换句话说就是在结束时必须引发NSInvalidArgumentException异常)
值得注意的是系统提供的-forwardingTargetForSelector:
方法是针对某个实例对象调用对象方法的,如果要调用类对象的类方法需要用
+forwardingTargetForSelector:
方法。
同样forwardInvocation
和methodSignatureForSelector
也遵循这样的方式修改为针对类对象方法的调用。
网友评论