3,消息转发机制

1,OC方法的调用

OC中的方法调用其实都是转成了objc_msgSend函数的调用,给receiver(方法调用者)发送了一条消息(selector方法名)
而objc_msgSend的执行流程又可以分为3个大的阶段:
1、消息发送阶段,
2、动态方法解析阶段,
3、消息转发阶段

1.1消息发送阶段:从类和父类的缓存列表和方法列表中查找方法

[receiver message]

在OC里面我们调用对象方法[Receiver message]的这种模式,实际是通过调用objc_msgSend(Receiver,message,…)函数来找到方法的实现入口。objc_msgSend实现原理通过对象对应的objc_object的ISA找到该类对应的objc_class结构体。通过依次遍历objc_cacheobjc_method_list里面的方法找到方法实际入口,如果没有找到则跳到父类寻找,以此类推如果最终都没有找到就会发生动态解析阶段

1.2动态方法解析阶段:如果消息发送阶段没有查找到方法, 就进入动态解析阶段, 负责动态添加方法的实现.

消息发送阶段我们类或者父类中仍然没有找到方法的实现,那么系统会去看我们是否是动态实现了该方法,如果是实例方法,会调用对象所在类的+ (BOOL)resolveInstanceMethod:(SEL)sel,如果是类方法,会调用 + (BOOL)resolveClassMethod:(SEL)sel

Person.h
#import 
@interface Person : NSObject
@end
Person.m
#import "Person.h"
#import 
void setNameImp(id self, SEL _cmd, NSString *name){
    NSLog(@"%@",name);
}

@implementation Person

+ (BOOL)resolveInstanceMethod:(SEL)sel{
    NSLog(@"%s",__FUNCTION__);
    if(sel == @selector(setName:)){
        class_addMethod(self, sel, (IMP)setNameImp, "v@:@");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
@end


main.m
#import 
#import "Person.h"
int main(int argc, const char * argv[]) {
  @autoreleasepool {
    Person *p = [[Person alloc] init];
    [p performSelector:@selector(setName:) withObject:@"百客"];
  }
  return 0;
}

1.3消息转发阶段:如果前两个阶段都没有找到方法, 就会进入消息转发阶段, 将消息转发给可以处理消息的消息接受者来处理.

1.3.1转移消息的接收者

- (id)forwardingTargetForSelector:(SEL)aSelector

通过- forwardingTargetForSelector:可以转移消息的接收者,如果有别的对象可以实现该方法,就直接让那个对象来处理该消息。不管另一对象的方法是公有还是私有,只要实现了就行

1.3.2完整转发

如果上述方式没有对转发的消息做处理,那么系统就会走完整的转发流程。系统会先通过 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector方法,来询问一个方法签名,如果这个方法返回了正确的方法签名, 就会调用- (void)forwardInvocation:(NSInvocation *)anInvocation方法. 如果未能找到就会调用-[NSObject(NSObject) doesNotRecognizeSelector:]

所以消息转发总结如下:


3,消息转发机制_第1张图片
i消息转发步骤.png

ps:详细解析推荐:
iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制

你可能感兴趣的:(3,消息转发机制)