iOS之方法的快速查找流程总结

875 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

快速查找流程:

  • 将类对象地址,内存平移16字节,取地址,得到cache首地址,即:_bucketsAndMaybeMask
  • _bucketsAndMaybeMask & bucketsMask,获取buckets首地址
  • 判断_bucketsAndMaybeMask0号位不为0,进入LLookupPreopt流程,查找共享缓存
  • 否则,通过_bucketsAndMaybeMask >> 48,得到mask
  • (_cmd ^ (_cmd >> 7)) & mask,得到下标i。源码中的cache_hash函数
  • 通过i * 16得到偏移值,buckets首地址+偏移值,得到指定下标的bucket
  • 流程1
    • 读取bucket_t中的impsel
    • 通过bucket_t - 16字节,读取上一个bucket
  • 流程2
    • 如果sel存在,并且等于_cmd,进入CacheHit缓存命中流程 - CacheHit流程:使用imp = imp ^ cls解码
    • 跳转到指定imp函数地址
  • 流程3
    • 如果sel不存在,进入__objc_msgSend_uncached流程
    • 上一个bucket地址和buckets首地址比较,如果>=,进入流程1
    • 否则,<首地址,获取mask下标的bucket,进入流程4
  • 流程4
    • 读取bucket_t中的impsel
    • 通过bucket_t - 16字节,读取上一个bucket
    • 如果sel等于_cmd,进入流程2
    • 如果sel存在,并且上一个bucket地址>指定下标bucket地址,进入流程4
    • 否则,进入__objc_msgSend_uncached流程

消息快速查找流程中,如果无法命中缓存,进入MissLabelDynamic流程。而MissLabelDynamic即是调用CacheLookup时传入的__objc_msgSend_uncached 流程探索:

  • 核心流程:__objc_msgSend_uncachedMethodTableLookup_lookUpImpOrForward
  • lookUpImpOrForward函数,并且不是汇编代码实现,而是C/C++函数
  • 汇编和C/C++的相互调用:
    • C/C++中调用汇编,在汇编代码中查找时,在方法名称最前面加一个下划线
    • 汇编中调用C/C++函数,在C/C++代码中查找时,去掉方法名称最前面的一个下划线