OC底层探索(九):cache 到 objc_msgSend

201 阅读1分钟

cache_t 读取流程分析

  • insert 方法打上断点,查看

image.png

  • 发现写入缓存之前地调用的是log_and_fill_cache
  • 再之前是lookUpImpOrForward
  • 然后就是objc_msgSend_uncached
  • 看来这个写入是在方法调用走消息发送的时候调用的

runtime运行时理解

  • OC编译成C++
[peson say];
[person sayHello];
((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("say"));

((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("sayHello"));
  • 调用方法 其实就是发送消息 = objc_msgSend(id, cmd), id 是消息的接受者就是对象, cmd = sel + 参数,也就是消息主体
  • 所以我们也可以这样来调用方法objc_msgSend(person, sel_registerName("sayHello")), objc_msgSend(person, @selector(sayHello))
  • 需要导入头文件#import <objc/message.h>

image.png

image.png

  • 子类声明了方法,但没有方法的实现,父类方法的实现
  • 子类调用该方法时,不会crash,而是会调用父类方法实现

image.png

  • +方法同样也不会crash,所以方法会向上查找,直到找到有实现该方法的父类
  • 反之,子类有实现,而父类没有,父类的对象调用,则会crash
  • objc_msgSendSuper也可以直接给父类发送消息,也就是直接调用父类的方法
struct objc_super wlw_objc_super;
wlw_objc_super.receiver = person;
wlw_objc_super.super_class = LGPerson.class;
objc_msgSendSuper(&wlw_objc_super,@selector(look));

objec_msgSend流程

  • objec_msgSend 在底层是使用汇编代码写了,为了更高效,快速

image.png

  • 不同架构下汇编代码,我们主要就看arm64真机的代码
  • 找到 ENTRY入口

image.png

image.png

  • cmp(比较) p0 是否为空,也就是isa是否是空的
  • b.le(<= 跳转),b.eq(= 跳转) 如果是空的并且支持 tagged pointer, 查找一下是否有 tagged pointer,没有则返回 zero, 并结束消息查找流程
  • 如果不为空,则通过 isa&ISA_MASK拿到,赋值给p16
  • 然后会走缓存查找流程,查找imp快速查找流程或者走 objc_msgSend_uncached也就是慢速查找流程