消息机制: 调用任何方法的时候 其实都相当于给这个对象发送一个消息
举例 如下方法
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self test]; // Do any additional setup after loading the view. } - (void)test{ NSLog(@"%@",self); //<ViewController: 0x104e089b0> NSLog(@"%@",NSStringFromSelector(_cmd)); //test } @end
每一个方法的调用其实默认都携带了两个参数 一个是 id 类型的self 一个是SEL 类型的_cmd
_cmd 其实是方法编号
在发送这个消息的时候、系统会根据方法编号去方法缓存列表查询方法(汇编查询效率较高)
如果缓存中未找到开启慢速查找 按照实例对象-> 类对象 -> 元类对象的顺序查找 (实例方法存在去类对象中、类方法存在于元类对象中) 如果找到就缓存起来
如果没找到就会进入动态方法解析阶段 如下 Person 没有实现run 进入消息动态放解析阶段时、可以动态添加方法
@interface Person : NSObject - (void)run; @end #import "Person.h" #import <objc/message.h> @implementation Person /* 动态解析 对象方法 */ + (BOOL)resolveInstanceMethod:(SEL)sel { if (sel == @selector(run)) { class_addMethod(self, sel, (IMP)dynamicMethod, "v@:"); return YES; } return [super resolveInstanceMethod:sel]; } void dynamicMethod(){ NSLog(@"%s",__func__); } @end
如果还没没有找到则进入消息转发流程
- (id)forwardingTargetForSelector:(SEL)aSelector{ if (aSelector == @selector(run)) { return [[Cat alloc] init]; } return [super forwardingTargetForSelector:aSelector]; } /* 如果没有实现forwardingTargetForSelector 就会调用下面的返回方法签名 如果返回了方法签名就会调用forwardInvocation 否则直接调用doesNotRecongnizeSelector */ - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ if (aSelector == @selector(run)) { return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation{ [anInvocation invokeWithTarget:[[Cat alloc] init]]; NSLog(@"anInvocation"); } void dynamicMethod(){ NSLog(@"%s",__func__); } @end