博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OC消息转发机制
阅读量:6272 次
发布时间:2019-06-22

本文共 2436 字,大约阅读时间需要 8 分钟。

前言

在上一篇中我们了解了消息的响应过程,即

  1. 先缓存查找,若未找到
  2. 接下来查找本类的方法列表查找,若未找到
  3. 则递归继承体系查找父类的方法列表直到NSObject

在第二第三步过程中,如果找到了则响应消息,并填充缓存,缓存是保存在元类上的,如果还找不到,则进入接下来的消息转发流程。

消息转发流程也分为三个步骤,动态解析 -> 前端转发 -> 方法签名转发,流程如下:

我们结合一个实例来具体看看

动态解析

第一步,当没找到方法时,你可以通过+ (BOOL)resolveInstanceMethod:(SEL)sel+ (BOOL)resolveClassMethod:(SEL)sel来添加实例方法和类方法

这里我们在ViewController中直接调用了QFPersonrun方法,但是QFPerson并没有实现这个方法,所以动态添加了这个方法。

+ (BOOL)resolveInstanceMethod:(SEL)sel {        if (sel == @selector(run:age:)) {//第一步自己添加方法        class_addMethod(self, sel, (IMP)newRun, "v@:@:");        return YES;    }    return [super resolveInstanceMethod:sel];}复制代码

这个添加一个自定义的方法

void newRun(id self,SEL sel, NSString *str, NSInteger age) {//自定义方法实现    NSLog(@"---run ok---%@---%ld",str,(long)age);}复制代码

这里用到了runtime的动态添加方法,不熟悉的可以看看这个系列文章的前几篇 ,执行结果:

QFMessageForwardDemo[18572:704661] ---run ok---hello---18复制代码

前端转发

如果第一步没有动态添加方法,则会进入转发的第二步,前端转发,所谓前端转发即是,本类没有实现这个方法,但是另外的一个类实现了这个方法,那么我们可以直接转发这条消息到另外的类实现调用。这里我们新建QFOtherPerson```` 并且实现- (void)run:(NSString *)name age:(NSInteger)age```方法

- (void)run:(NSString *)name age:(NSInteger)age{    NSLog(@"%@ 执行了 run name = %@,age = %ld",NSStringFromClass([self class]), name,age);}复制代码

QFPerson的实现文件中,实现下面的方法完成转发

- (id)forwardingTargetForSelector:(SEL)aSelector {    return [[QFOtherPerson alloc]init];//第二步,前端转发}复制代码

ps:此时要先注释注释掉第一步的动态添加方法

执行结果:

QFMessageForwardDemo[19629:739692] QFOtherPerson 执行了 run name = hello,age = 18复制代码

签名转发

第三步,也是最后的机会处理这条消息了,首先生成方法签名:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {//第三步,签名转发    NSString *methodName = NSStringFromSelector(aSelector);    if ([methodName isEqualToString:@"run:age:"]) {//是我们需要转发的run方法        return [NSMethodSignature signatureWithObjCTypes:"v@:"];    } else {        return [super methodSignatureForSelector:aSelector];    }}复制代码

关于invocation你熟悉的可以看这里面有完整的invocation调用方法的例子,这里就不做粘贴了。

最后调用-forwardInvocation:指定target,完成转发:

- (void)forwardInvocation:(NSInvocation *)anInvocation {//签名转发    SEL selector = [anInvocation selector];//目标方法    QFOtherPerson *other = [[QFOtherPerson alloc]init];//转发对象    if ([other respondsToSelector:selector]) {//目标对象能相应此方法        [anInvocation invokeWithTarget:other];    } else {        return [super forwardInvocation:anInvocation];    }}复制代码

运行结果:

QFMessageForwardDemo[31317:930989] QFOtherPerson 执行了 run name = hello,age = 18复制代码

以上就是方法转发的流程,如果以上三步都没有实现则会崩溃,显示一个很常见的异常**- unrecognized selector sent to instance 0x60000001b440'**

关于之前的流程请参考:

转载地址:http://fmlpa.baihongyu.com/

你可能感兴趣的文章
重叠(Overlapped)IO模型
查看>>
ffmpeg study 1
查看>>
Git使用教程
查看>>
使用shell脚本自动监控后台进程,并能自动重启
查看>>
Flex&Bison手册
查看>>
MySQL 5.6 for Windows 解压缩版配置安装
查看>>
solrCloud+tomcat+zookeeper集群配置
查看>>
/etc/fstab,/etc/mtab,和 /proc/mounts
查看>>
Apache kafka 简介
查看>>
socket通信Demo
查看>>
技术人员的焦虑
查看>>
js 判断整数
查看>>
建设网站应该考虑哪些因素
查看>>
mongodb $exists
查看>>
js实现页面跳转的几种方式
查看>>
sbt笔记一 hello-sbt
查看>>
常用链接
查看>>
pitfall override private method
查看>>
!important 和 * ----hack
查看>>
聊天界面图文混排
查看>>