今天突然又兴趣看了下 NSObject的头文件,发现其中的消息转发机制还不甚了解,所以在 debug 调试了解之后,写下此文章留作记录
1 | - (id)forwardingTargetForSelector:(SEL)aSelector; |
2 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector; |
3 | + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector; |
4 | - ( void )forwardInvocation:(NSInvocation *)anInvocation; |
5 | - ( void )doesNotRecognizeSelector:(SEL)aSelector; |
调用顺序如上面函数顺序
当使用如下函数调用
2 | [someObj performSelector:@selector(method1)]; |
如果 someObj没有实现 method1函数
runtime 将会调用
1 | - (id)forwardingTargetForSelector:(SEL)aSelector |
3 | if ([SomeObj respondsToSelector:aSelector]) { |
如果 SomeObj 能够响应 aSelector,我们就将此消息转发到 someObj.
如果SomeObj 不能响应,函数返回了 nil
此时 runtime system将调用
1 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector |
3 | NSMethodSignature *signature = [super methodSignatureForSelector:aSelector]; |
4 | if (signature == nil) { |
5 | signature = [OtherObj instanceMethodSignatureForSelector:aSelector]; |
如果父类没有实现此SEL,就询问 OtherObj 是否实现此 SEL
如果实现就返回NSMethodSignature
否则就返回 nil,此时 runtime system就会调用
1 | - ( void )doesNotRecognizeSelector:(SEL)aSelector |
3 | NSLog(@ "%@ %@" ,NSStringFromClass(self. class ),NSStringFromSelector(_cmd)); |
表示没有实现此函数,并抛出NSInvalidArgumentException
异常
可以在此函数中做程序最后的处理
说回去,如果OtherObj实现了此函数,则 runtime system 会调用
1 | - ( void )forwardInvocation:(NSInvocation *)anInvocation |
3 | if ([OtherObj instancesRespondToSelector:[anInvocation selector]]) |
4 | [anInvocation invokeWithTarget:otherObj]; |
6 | [super forwardInvocation:anInvocation]; |
这样写是为了让父类的转发不被覆盖,这里如果不调用
1 | [anInvocation invokeWithTarget:otherObj]; |
将不会真正调用函数
到此,转发的方式与过程叙述完毕
转载:http://my.oschina.net/u/811205/blog/175537