深入理解iOS消息转发机制

消息转发流程图

image

向一个对象发送消息时, 首先会在对象类的cache,method list以及父类对象的cache,method list依次查找SEL对应的IMP

如果没有找到,并且实现了动态方法决议机制就会决议。如果没有实现动态决议机制或者决议失败且实现了消息转发机制。就会进入消息转发流程。否则程序Crash.

进入消息转发 objc——msgSend(id, SEL,...)来实现消息转发

动态方法决议

字面上我的理解是:消息在发送过程中进行判断到底这消息该由谁接收

一:询问是否有动态添加方法来进行处理

Objective C 提供了一种名为动态方法决议的手段,使得我们可以在运行时动态地为一个 selector 提供实现。我们只要实现

+resolveInstanceMethod: 
+resolveClassMethod: 

并在其中为指定的 selector 提供实现即可(通过调用运行时函数 class_addMethod 来添加)。这两个方法都是 NSObject 中的类方法 实现

//People.m
void speak(id self, SEL _cmd){
    NSLog(@"Now I can speak.");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"resolveInstanceMethod:  %@", NSStringFromSelector(sel));
    if (sel == @selector(speak)) {
        class_addMethod([self class], sel, (IMP)speak, "V@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

+ (BOOL)resolveClassMethod:(SEL)name  
{  
    NSLog(@" >> Class resolving %@", NSStringFromSelector(name));  
      
    return [super resolveClassMethod:name];  
}

二:询问有没有别人能够帮忙处理一下

 - (id)forwardingTargetForSelector:(SEL)aSelector

使用如下

- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"forwardingTargetForSelector:  %@", NSStringFromSelector(aSelector));
    Bird *bird = [[Bird alloc] init];
    if ([bird respondsToSelector:aSelector]) {
        return bird;
    }
    return [super forwardingTargetForSelector: aSelector];
}
// Bird.m
- (void)fly {
    NSLog(@"I am a bird, I can fly.");
}

三:在一和二中都没能处理掉时会进入

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
    if ([anInvocation selector] == @selector(code)) {
        Monkey *monkey = [[Monkey alloc] init];
        [anInvocation invokeWithTarget:monkey];
    }   
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));
    if (aSelector == @selector(code)) {
        return [NSMethodSignature signatureWithObjCTypes:"V@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

END

最后消息未能处理的时候,还会调用到

- (void)doesNotRecognizeSelector:(SEL)aSelector

我们也可以在这个方法中做些文章,避免掉crash,但是只建议在线上环境的时候做处理,实际开发过程中还要把异常抛出来

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

RCTEventEmitter使用

在0.27版本之前,RN的Native端向js端发射消息主要通过sendDeviceEventWithName的方式,相关代码如下。 @synthesize b...

2807
来自专栏哈雷彗星撞地球

iOS 中如何判断当前是2G/3G/4G/5G/WiFi

5G 什么的,还得等苹果API更新啊,不过将来还是这个处理过程就是了。 关于判断当前的网络环境是2G/3G/4G,这个问题以前经常看到,最近在一工程里看到了如...

1342
来自专栏DannyHoo的专栏

KVO代码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

911
来自专栏Alice

iOS 获取通讯录里边的电话号码AddressBook

1  首先导入库 <AddressBook/AddressBook.h> 2 然后在导入#import <AddressBook/AddressBook.h>文...

25210
来自专栏转载gongluck的CSDN博客

第14章 高级I/O函数

设置套接字时间限制: 1、使用alarm函数和SIGALRM信号 2、使用由select提供的时间限制 3、使用SO_RCVTIMEO和SO_SNDTIM...

2834
来自专栏技术之路

ios 接收 c# socket udp 组播

最近用wcf 服务 给ios和安卓做接口,做了几个ios的项目  用udp 组播 让ios多终端接收和刷新方法 做一个简单的小例子会把工程给大家下载的   c#...

2248
来自专栏Python小屋

Python模拟汉诺塔问题移动盘子的过程

据说古代有一个梵塔,塔内有三个底座A、B、C,A座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个和尚想把这64个盘子从A座移到C座,但每次只能允许移动...

4606
来自专栏雨尘分享

ReactiveCocoa 入门知识——归总篇

1994
来自专栏陈满iOS

[iOS源码笔记]·第三方网络图片处理框架:SDWebImage网络下载及缓存管理策略

typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _N...

731
来自专栏iOS开发攻城狮的集散地

UIActivityViewController系统原生分享-仿简书分享

3198

扫码关注云+社区