OC中的方法调用,其实都是转化为objc_msgSend
函数的调用,objc_mesgSend
的执行流程可分为3个阶段
- 消息发送
- 动态方法解析
- 消息转发
消息转发
动态方法解析
开发者可以实现以下的办法来实现动态添加方法实现
- +resolveInstanceMethod:
- +resolveClassMethod:
动态解析后会重新走消息发送的流程,从receiveClass
的cache
中查找方法这一步开始执行
创建一个Person类,然后在.h文件中写一个- (void)test,但是不写具体实现,然后调用.会打印出最常见的unrecognized selector sent to instance.
- (void)other{
NSLog(@"%s",__func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
//获取其他方法
Method method = class_getInstanceMethod(self, @selector(other));
//动态添加test的方法
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super resolveInstanceMethod:sel];
}
消息转发
如果一个方法在消息发送阶段
没有找到相关方法,也没有进行动态方法解析
,这个时候就会走到消息转发阶段
了.
forwardingTargetForSelector
创建两个类Person和Student,在Person.h里面写一个实例方法,但是不去实现相关方法。
在Person里面实现这个方法
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(test)) {
return [[Student alloc]init];
}
return nil;
}
调用forwardingTargetForSelector
,返回值不为nil
时,会调用objc_msgSend(返回值, SEL
),结果就是调用了objc_msgSend(Student,test)
methodSignatureForSelector(方法签名)
当forwardingTargetForSelector
返回值为nil
,或者都没有调用该方法的时候,系统会调用methodSignatureForSelector
方法。调用methodSignatureForSelector
,返回值不为nil
,调用forwardInvocation:
方法;返回值为nil
时,调用doesNotRecognizeSelector:
方法
对于方法签名的生成方式
- [NSMethodSignature signatureWithObjCTypes:"i@:i"]
- [[[Student alloc]init] methodSignatureForSelector:aSelector];
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(test)) {
return [[[Student alloc]init]methodSignatureForSelector:aSelector];
// return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@"=======");
}
NSInvocation
中封装了一个方法调用,包括方法调用者,方法名,方法参数.
- anInvocation.target 方法调用者
- anInvocation.selector 方法名
- [anInvocation getArgument:NULL atIndex:0]