一些概念
静态绑定:在编译期就能决定运行时所应调用的函数。代表语言:C、C++等
动态绑定:所要调用的函数直到运行期才能确定。代表语言:OC、swift等
消息传递:对象正常解读消息,传递过去
消息转发:对象无法解读消息,之后进行消息转发
消息处理流程
- OC中调用方法
[a method]
后都是在执行id objc_msgSend(id self, SEL op, ...)
id objc_msgSend(id self, SEL op, ...)
是一个参数个数可变的函数,第一参数代表接受者,第二个参数代表选择子(OC函数名),之后的参数就是消息中传入的参数。 -
objc_msgSend
函数会在接收者所属的类中搜寻其方法列表,如果能找到这个跟选择子名称相同的方法,就跳转到其实现代码,往下执行。 - 若是当前类没找到,那就沿着继承体系继续向上查找,等找到合适方法之后再跳转
- 如果最终还是找不到,那就进入消息转发的流程去进行处理。
消息转发流程
- 调用resolveInstanceMethod:征询接受者(所属的类)是否可以添加方法以处理未知的选择子?(此过程称为动态方法解析)若有,转发结束。若没有,走第二步。
- 调用forwardingTargetForSelector:询问接受者是否有其他对象能处理此消息。若有,转发结束,一切如常。若没有,走第三步。
- 调用forwardInvocation:运行期系统将消息封装到NSInvocation对象中,再给接受者一次机会。
- 以上三步还不行,就抛出异常:unrecognized selector sent to instance xxxx
消息转发实例
- 在ViewController的头文件中声明一个方法,但是不要在ViewController.m中实现
ViewController.h #import <UIKit/UIKit.h> @interface ViewController : UIViewController - (void)testForwardMethod; @end
- 在AppDelegate中调用ViewController的
testForwardMethod
方法AppDelegate.m [[[ViewController alloc] init] testForwardMethod];
- 这时候编译没有问题,但是运行会出现
-[ViewController testForwardMethod]: unrecognized selector sent to instance 0x10581bfe0
- 在ViewController.m中增加消息转发的方法
ViewController.m - (id)forwardingTargetForSelector:(SEL)aSelector { NSLog(@"ViewController forwardingTargetForSelector"); return [[TestView alloc] init]; } // 如果有方法的实现,所有消息转发的过程都不会进行 //- (void)testForwardMethod //{ // NSLog(@"ViewController testForwardMethod"); //} TestView.m - (void)testForwardMethod { NSLog(@"TestView testForwardMethod"); }
- (id)forwardingTargetForSelector:(SEL)aSelector; 把aSelector转发给其他类对象。
- 在ViewController.m中增加两个消息转发的方法
ViewController.m - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSLog(@"ViewController methodSignatureForSelector"); if (aSelector == @selector(testForwardMethod)) { NSLog(@"ViewController methodSignatureForSelector equal"); return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { NSLog(@"ViewController forwardInvocation:"); }
-
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
返回一个NSMethodSignature对象,该对象包含给定选择器标识的方法的描述。在方法转发过程中如果需要使用NSInvocation
则就需要使用这个方法。 -
signatureWithObjCTypes:
是用C字符串来创建NSMethodSignature
对象,详细的描述可以看这篇文章
-
首发在我的个人博客