Runtime 总结笔记“消息”和“消息转发”

参考文章: runtime

本文章为原创,转载请注明出处

Objc_msgSend

动态绑定 & 静态绑定
  • 静态绑定:在编译期就能决定运行时所调用的函数
  • 动态绑定:在运行时(runtime)传递消息进行动态查找
objc_msgSend函数
id returnValue = [someObject messageName: parameter];
[receiver message]; 
/// 转为
objc_msgSend(receiver, selector, parameter);
  • messageName叫选择子,和参数合称消息
  • 在Objective-C消息不会被绑定,直到runtime编译器将消息表达式转换为一个消息调用函数,其中 “接收者” 和 “Selector” 为主要参数
objc_msgSend做了什么
  • 在运行时,先查找selector的实现,因为同样的方法可以被不同的类所实现,所以查找方法实现的过程需要取决于接收者
  • 然后调用这段方法的实现,传入 “接收者中对象的数据” 和实现 “当前方法所需要的参数”,因为有时方法的实现可能取决于接受者的实例变量
  • 最后将这个方法的返回值作为自己的返回值返回
  • 消息传递依赖 “类” 和 “对象” 的数据结构,比如isa,super_class,method_list,cache
objc_msgSend在继承层级中查找方法
  • 当对象被创建,分配好内存,实例变量被初始化后,对象的第一个实例变量是一个 “isa” 指针,指向它的类结构,通过isa指针可以获取类对象的结构体,从而获取到元类对象,类对象的父类
  • 当一个消息从对象上发送,如没有找到选择子,这条消息沿着对象的isa指针和super_class指针,沿着类对象和元类对象的继承体系一直查找到根类对象,一般为NSObject,一旦定位到方法,objc_msgSend会在方法表列里调用这条方法,传入该对象的数据结构。
    在这里插入图片描述
方法缓存加速查找
  • 为了加速查找,runtime会缓存找到的方法和他们的地址,也会缓存该类的方法列表和superClass的方法,在查找前,会先查看接受者的缓存表列(cache),如果方法被缓存了,就直接调用,当程序预热一段时间后,几乎所有的方法都能在缓存中找到

动态方法解析和消息转发

对象收到无法解读的方法后使用动态方法解析

unrecognized selector sent to instance 0x87

控制台中打印这条消息,消息发送和消息转发都没有能解决该消息,最后调用了NSObject的方法doesNotRecognizeSelector的默认实现

  1. 通过resolveInsanceMethod: 方法决定是否动态添加方法,返回YES则调用class_addMethod动态添加方法,调用并结束,一般用于@dynamic属性
  2. 进入forwardingTargetForSelector: 方法,用于指定备援接受者来响应这个selector,不能指定self,如果返回某个对象则调用该对象上的方法,结束,如果返回nil进入第三步
  3. 通过methodSignatureForSelector: 方法签名,返回nil则消息无法处理,返回methodSignature则进入完整的消息转发
  4. 调用forwardingInvocaiton: 方法, 可以通过anInvocation对象做很多处理,比如修改实现方法,修改响应对象,方法调用完成就结束,不然进入doesNotRecognizeSelector: 方法的默认实现并Crash
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值