iOS 消息转发机制
消息机制: 调用任何方法的时候 其实都相当于给这个对象发送一个消息
举例 如下方法
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self test]; // Do any additional setup after loading the view. } - (void)test{ NSLog(@"%@",self); //<ViewController: 0x104e089b0> NSLog(@"%@",NSStringFromSelector(_cmd)); //test } @end
每一个方法的调用其实默认都携带了两个参数 一个是 id 类型的self 一个是SEL 类型的_cmd
_cmd 其实是方法编号
在发送这个消息的时候、系统会根据方法编号去方法缓存列表查询方法(汇编查询效率较高)
如果缓存中未找到开启慢速查找 按照实例对象-> 类对象 -> 元类对象的顺序查找 (实例方法存在去类对象中、类方法存在于元类对象中) 如果找到就缓存起来
如果没找到就会进入动态方法解析阶段 如下 Person 没有实现run 进入消息动态放解析阶段时、可以动态添加方法
@interface Person : NSObject - (void)run; @end #import "Person.h" #import <objc/message.h> @implementation Person /* 动态解析 对象方法 */ + (BOOL)resolveInstanceMethod:(SEL)sel { if (sel == @selector(run)) { class_addMethod(self, sel, (IMP)dynamicMethod, "v@:"); return YES; } return [super resolveInstanceMethod:sel]; } void dynamicMethod(){ NSLog(@"%s",__func__); } @end
如果还没没有找到则进入消息转发流程
- (id)forwardingTargetForSelector:(SEL)aSelector{ if (aSelector == @selector(run)) { return [[Cat alloc] init]; } return [super forwardingTargetForSelector:aSelector]; } /* 如果没有实现forwardingTargetForSelector 就会调用下面的返回方法签名 如果返回了方法签名就会调用forwardInvocation 否则直接调用doesNotRecongnizeSelector */ - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ if (aSelector == @selector(run)) { return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation{ [anInvocation invokeWithTarget:[[Cat alloc] init]]; NSLog(@"anInvocation"); } void dynamicMethod(){ NSLog(@"%s",__func__); } @end
实际应用 利用消息转发机制 可以避免开发中的一些 unrecognized selector sent to崩溃
@interface Cat : NSObject - (void)run; - (void)walk; @end #import "Cat.h" @implementation Cat - (void)run{ NSLog(@"%s",__func__); } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ if ([self respondsToSelector:aSelector]) { return [super methodSignatureForSelector:aSelector]; } return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } - (void)forwardInvocation:(NSInvocation *)anInvocation{ NSLog(@"没有找到%@",NSStringFromSelector(anInvocation.selector)); } @end
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2017-04-27 swift项目初始化并添加忽略文件Swift.ignore
2017-04-27 开源中国社区 https://git.oschina.net/ 添加 SSH 公钥 添加