runtime中的消息转发

作者: 我系哆啦 | 来源:发表于2016-04-05 23:46 被阅读147次

一直以来,都知道object-c是支持消息转发的,也就是说它可以使一个类响应另外一个类中实现的消息(方法)。到底具体动态转发具体的过程是怎么样的.用代码说话.通过比较普通的方法调用和通过消息转发的方法调用来一探究竟.下面新建个简单的car类.


<pre>
@interface Car : NSObject

  • (instancetype)car;
    @property (nonatomic, copy) NSString *carInfo;
    @end
    </pre>

<pre>
@implementation Car
-(instancetype)init{
self = [super init];
if (self) {
_carInfo = @"This Is A Car";
}
return self;
}
+(instancetype)car{
return [[self alloc] init];
}
@end
</pre>

普通的方法调用

<pre>
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
Car *myCar = [Car car];
NSString * upperStr = [(NSString *)myCar uppercaseString];
NSLog(@"%@--%@",myCar.carInfo,upperStr);
}
</pre>

  • 普通的方法调用中,发送消息给一个无法处理该选择器(uppercaseString)的对象myCar,因为Car对象无法响应uppercaseString,且消息转发后也没有合适的对象响应uppercaseString(转发过程是怎么样的下面会说).所以程序奔溃了,错误提示是常见的-[Car uppercaseString]: unrecognized selector sent to instance 0x7fe498cb3cd0;通过下图,我们可以看出,-[NSObject(NSObject) doesNotRecognizeSelector:] + 205之前有forwarding + 970这条代码,这个应该就是消息转发了,消息转发之后仍然没有对象响应该方法,所以程序最后抛出unrecognized selector sent to instance 0x7fe498cb3cd0 的经典错误了.
未实现消息转发功能的方法调用结果

实现消息转发功能的方法调用

在给程序添加消息转发功能以前,必须覆盖两个方法,即methodSignatureForSelector: 和 forwardInvocation:。

  • methodSignatureForSelector:的作用在于为另一个类实现的消息创建一个有效的方法签名。
  • forwardInvocation:将选择器转发给一个真正实现了该消息的对象.

在Car.m文件中重写上面两个方法

<pre>
//采用迭代的方式为当前被调用的方法创建一个有效的签名
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
if (!signature) {
signature = [self.carInfo methodSignatureForSelector:aSelector];
}
return signature;
}
//得到签名后,转入forwardInvocation:方法对其调用的方法(UTF8String)进行实现.
-(void)forwardInvocation:(NSInvocation *)anInvocation{
SEL aSelector = [anInvocation selector];
if ([self.carInfo respondsToSelector:aSelector]) {
[anInvocation invokeWithTarget:self.carInfo];
}
}
</pre>
同样调用方法:
<pre>
-(void)touchesBegan:(NSSet<UITouch *> )touches withEvent:(UIEvent )event{
Car *myCar = [Car car];
NSString *upperStr = [(NSString *)myCar uppercaseString];
NSLog(@"%@--%@",myCar.carInfo,upperStr);
}
</pre>
神奇的事情发生了:

实现消息转发功能的方法调用结果
  • 具体是怎么实现的呢,self.carInfo是一个NSString对象,存在于Car类中.Car实例是无法正确的为另外一个对象(NSString)实现的选择器创建一个有效的签名。运行时当检查到当前没有有效的签名,即进入该对象(这里是myCar)的methodSignatureForSelector:方法中,此时,在这个方法中进行迭代并尝试构建一个有效的方法签名的机会.例如代码中,当myCar调用uppercaseString时,由于无法从当前对象中获得消息,转入第二次机会捕捉消息,首先进入methodSignatureForSelector:方法,采用迭代的方式为当前被调用的方法创建一个有效的签名,得到签名后,转入forwardInvocation:方法对其调用的方法(uppercaseString)进行实现. forwardInvocation:中,首先获得调用的方法(uppercaseString),判断self.carInfo(一个nsstring对象)能否响应该方法,如果可以,将调用uppercaseString对象的目标转换为self.carInfo对象. 这样 ,我们就实现了消息转发.

相关文章

  • Effective Objective-C读后笔记(2)

    11、runtime消息转发机制 runtime的消息转发流程图消息转发 消息转发的示例实现 这里也给大家推荐一篇...

  • runtime中的消息转发

    一直以来,都知道object-c是支持消息转发的,也就是说它可以使一个类响应另外一个类中实现的消息(方法)。到底具...

  • runtime中的消息转发

    1动态方法解析 如果一个对象调用了在这个类中方法列表中找不到选择子(SEL),这个时候可以使用为这个选择子添加一个...

  • iOS - Runtime - 概念和方法交换

    runtime的概述runtime的相关概念runtime消息机制消息传递动态方法解析消息转发runtime的作用...

  • runtime底层实现原理

    一、Runtime介绍二、Runtime源码初探三、Runtime消息传递四、Runtime消息转发五、Runti...

  • Runtime

    Runtime的特性主要是消息(方法)的传递,如果消息(方法)在对象中找不到,就会进行转发。 Runtime的介绍...

  • 2022-04-12

    RunTime基础详解 Runtime的特性主要是消息(方法)传递,如果消息(方法)在对象中找不到,就进行转发,具...

  • Runtime-原理

    runtime初探对象与方法的本质runtime-消息发送runtime-动态方法解析runtime-消息转发 r...

  • runtime 消息转发

    实例方法的消息传递:消息的转发建立在objc_msgSend(id, SEL, ...)来实现的。首先会在类对象的...

  • Runtime 消息转发

    目录 消息转发背景知识 消息转发使用方式 消息转发常见问题 消息转发背景知识 1.消息转发的定义Objective...

网友评论

    本文标题:runtime中的消息转发

    本文链接:https://www.haomeiwen.com/subject/ncnplttx.html