IOS 消息转发机制

参考文章:

http://www.jianshu.com/p/1bde36ad9938

http://tech.glowing.com/cn/objective-c-runtime/

Objective-C Runtime 运行时之三:方法与消息


Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石。

Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递 (Messaging)。

OC中调用方法就是向对象发送消息。

比如 :
[person run];
这实际上这是在给person这个对象发送run这个消息。
那么问题来了,当run这个方法只有定义没有实现会怎么样呢?
就是经典的报错

ok,前提已经说完了,我们就从找这个错误原因讲起。

首先,该方法在调用时,系统会查看这个对象能否接收这个消息(查看这个类有没有这个方法,或者有没有实现这个方法。),如果不能并且只在不能的情况下,就会调用下面这几个方法,给你“补救”的机会,你可以先理解为几套防止程序crash的备选方案,我们就是利用这几个方案进行消息转发,注意一点,前一套方案实现后一套方法就不会执行。如果这几套方案你都没有做处理,那么程序就会报错crash。

打个比方:比赛足球时,脚下有球的那名球员,如果他的位置不利于射门或者他的球即将被对方球员抢断,这时最好是把球传出去,这里的球就相当于消息。


-(id)initWithName:(id)obj1 obj2:(id)obj2
{
    _realObj1 = obj1;
    _realObj2 =  obj2;
    return self;
}


-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    NSMethodSignature *s1;
    s1 = [_realObj1 methodSignatureForSelector:sel];
    if (s1) {  return s1;}
    s1 = [_realObj2 methodSignatureForSelector:sel];
    return s1;
}
-(void)forwardInvocation:(NSInvocation *)invocation
{
    id target = [_realObj1 methodSignatureForSelector:[invocation selector]]?_realObj1:_realObj2;
    [invocation invokeWithTarget:target];
    
}
-(BOOL)respondsToSelector:(SEL)aSelector
{
    if ([_realObj1 respondsToSelector:aSelector])  return YES;
    else if([_realObj2 respondsToSelector:aSelector])return YES;
    return NO;

}



- (void)viewDidLoad {
    [super viewDidLoad];
    NSMutableString *string = [[NSMutableString alloc]init];
    NSMutableArray *array = [[NSMutableArray alloc]initWithCapacity:10];
    id proxy = [[myProxy alloc]initWithName:string obj2:array];
    
    [proxy appendString:@"this "];
    [proxy addObject:string];
    [proxy appendString:@"is "];
    [proxy appendString:@"a "];
    [proxy appendString:@"proxy"];
    
    NSLog(@"this should be 1 it is %li",[proxy count]);
    
    if ([[proxy objectAtIndex:0] isEqualToString:@"this is a proxy"]) {
        NSLog(@"appendString Successful");        
    }
}


如果在prox中实现下面方法,程序会crash掉,原因,prox并没有实现appedString 和 addobject方法和count方法

系统就会调用两个方法methodSignatureForSelector和forwardInvocation

methodSignatureForSelector用来生成方法签名,这个签名就是给forwardInvocation中的参数NSInvocation调用的。

开头我们要找的错误unrecognized selector sent to instance原因,原来就是因为methodSignatureForSelector这个方法中,由于没有找到run对应的实现方法,所以返回了一个空的方法签名,最终导致程序报错崩溃。

所以我们需要做的是自己新建方法签名,再在forwardInvocation中用你要转发的那个对象调用这个对应的签名,这样也实现了消息转发。



-(void)forwardInvocation:(NSInvocation *)invocation
{
    id target = [_realObj1 methodSignatureForSelector:[invocation selector]]?_realObj1:_realObj2;
    [invocation invokeWithTarget:target];
    
}
-(BOOL)respondsToSelector:(SEL)aSelector
{
    if ([_realObj1 respondsToSelector:aSelector])  return YES;
    else if([_realObj2 respondsToSelector:aSelector])return YES;
    return NO;

}

程序的结果为string 会拼接字符串 this is a proxy

array会增加一个object,也就是 [proxy count]==1

且[proxy objectAtIndex:0] 就是 会转发到 [array objectAtIndex:0] 也就是@"this is a proxy",所以会成功输出

        NSLog(@"appendString Successful");        



欢迎转载:请尊重原创,注明出处  http://blog.csdn.net/lcg910978041/article/details/51902470

github地址:点击打开链接






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值