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

 

apple doc : https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html

讲解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:”以抛出异常,此异常表明选择子最终未能得到处理。

 

 

 

未完,待续....

posted on 2014-04-28 16:29  tinkl  阅读(704)  评论(0编辑  收藏  举报

导航