ios NSMethodSignature and NSInvocation 消息转发
1.首先获取消息转发时连个函数内部具体内容 MARK:这里是拿[@"xxxxx" length]调用拿来举例说明
(lldb) po signature <NSMethodSignature: 0x170076f80> number of arguments = 2 frame size = 224 is special struct return? NO return value: -------- -------- -------- -------- type encoding (Q) 'Q' flags {} modifiers {} frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0} memory {offset = 0, size = 8} argument 0: -------- -------- -------- -------- type encoding (@) '@' flags {isObject} modifiers {} frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0} memory {offset = 0, size = 8} argument 1: -------- -------- -------- -------- type encoding (:) ':' flags {} modifiers {} frame {offset = 8, offset adjust = 0, size = 8, size adjust = 0} memory {offset = 0, size = 8}
(lldb) po anInvocation <NSInvocation: 0x178075d80> return value: {Q} 0 target: {@} 0x17801e350 selector: {:} length
讲解type encoding具体用法:http://nshipster.com/type-encodings/
2. 具体案例:json解析数据时 NSJSONSerialization 会自动把他们换成 NSNull。当我们再去用dict[@“hello”]的时候,就会出触发exception,导致程序崩溃(ios6会出现)
两种实现:
第一种: #import "NSNull+OVNatural.h" @implementation NSNull (OVNatural) - (void)forwardInvocation:(NSInvocation *)invocation { if ([self respondsToSelector:[invocation selector]]) { [invocation invokeWithTarget:self]; } } - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { NSMethodSignature *sig = [[NSNull class] instanceMethodSignatureForSelector:selector]; if(sig == nil) { sig = [NSMethodSignature signatureWithObjCTypes:"@^v^c"]; } return sig; } @end
第二种: #define NSNullObjects @[@"",@0,@{},@[]] @interface NSNull (InternalNullExtention) @end @implementation NSNull (InternalNullExtention) - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector { NSMethodSignature* signature = [super methodSignatureForSelector:selector]; if (!signature) { for (NSObject *object in NSNullObjects) { signature = [object methodSignatureForSelector:selector]; if (signature) { break; } } } return signature; } - (void)forwardInvocation:(NSInvocation *)anInvocation { SEL aSelector = [anInvocation selector]; for (NSObject *object in NSNullObjects) { if ([object respondsToSelector:aSelector]) { [anInvocation invokeWithTarget:object]; return; } } [self doesNotRecognizeSelector:aSelector]; } @end
- (void)forwardInvocation:(NSInvocation *)anInvocation 只需改变调用目标,使消息在新目标上得以调用即可。然而这样实现出来的方法与“备援接收者”方案所实现的方法等效,所以很少有人采用这么简单的实现方式。比较有用的实现方式为:在触发消息前,先以某种方式改变消息内容,比如追加另外一个参数。
实现此方法时,若发现某调用操作不应由本类处理,则需调用超类的同名方法。这样的话,继承体系中的每个类都有机会处理此调用请求,直至NSObject。如果最后调用了NSObject类的方法,那么该方法还会继而调用“doesNotRecognizeSelector:”以抛出异常,此异常表明选择子最终未能得到处理。
未完,待续....