OC中的方法调用,其实都是转换为objc_megSend函数调用。
objc_megSend的执行流程可以分为3大阶段
- 消息发送,如果消息发送成功,则调用相关方法。如果失败进入下一阶段。
- 动态方法解析,如果成功,则调用相关方法。如果失败进入下一阶段。
- 消息转发,如果失败则会"报找不到方法错误"
消息发送流程
消息发送.png
动态方法解析
流程
动态方法解析.png
动态添加方法
当消息发送进入动态方法解析阶段,调用+resolveInstanceMethod:或+resolveClassMethod:方法时,可以在此时动态的添加方法。
有两种动态添加方法的方式。
-
动态其他OC方法
@interface GLPerson : NSObject - (void) abc; @end #import <objc/runtime.h> @implementation GLPerson - (void) other { NSLog(@"%@",NSStringFromSelector(_cmd)); NSLog(@"%s",__func__); } + (BOOL)resolveInstanceMethod:(SEL)sel { if (sel == @selector(abc)) { //将other方法的实现添加。Method可以理解为等价于struct method_t * Method method = class_getInstanceMethod(self, @selector(other)); class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method)); return YES; } return [super resolveInstanceMethod:sel]; } @end //// ===== main int main(int argc, const char * argv[]) { @autoreleasepool { GLPerson *person = [[GLPerson alloc] init]; [person abc]; } return 0; } //程序输出: //abc /-[GLPerson other] -
动态添加C语言函数
@interface GLPerson : NSObject - (void) abc; @end #import <objc/runtime.h> @implementation GLPerson - (void) other { NSLog(@"%@",NSStringFromSelector(_cmd)); NSLog(@"%s",__func__); } + (BOOL)resolveInstanceMethod:(SEL)sel { if (sel == @selector(abc)) { class_addMethod(self, sel, /* C语言的函数名就是函数地址 */ (IMP)other, "v16@0:8"); return YES; } return [super resolveInstanceMethod:sel]; } @end //// ===== main int main(int argc, const char * argv[]) { @autoreleasepool { GLPerson *person = [[GLPerson alloc] init]; [person abc]; } return 0; } //程序输出: //abc //self=<GLPerson: 0x10301a950>
消息转发流程
消息转发,顾名思义就是将消息转发给别的对象。
消息转发.png
当方法调用来到消息转发阶段:
-
会先调用
-forwardingTargetForSelector:或者+forwardingTargetForSelector:方法。-
如果返回值不为
nil,则objc_msgSend(返回值,sel)。 -
如果返回值为
nil或者没有实现,则进入第二个步骤 -
实例对象调用
-forwardingTargetForSelector:,类对象调用+forwardingTargetForSelector:
forwardingTargetForSelector_demo.png
-
-
如果返回值为
nil,则会调用-methodSignatureForSelector:或者+methodSignatureForSelector:,该方法要求返回一个方法签名。-
如果返回
nil,则会调用doesNotRecognizeSelector:抛出异常错误。 -
如果返回值不为
nil,则进入下一步骤
methodSignatureForSelector_demo.png
-
-
methodSignatureForSelector:返回值不为nil,则调用forwardInvocation:,这个方法中可以进行任意操作。并且也不会导致崩溃。
forwardingTargetForSelector_demo.png














网友评论