4.动态运行时(RunTime)
- 基础数据结构
- 对象、类对象、元类对象是怎么理解的?以及他们之间的关系是怎样的(实例与类对象之间的关系以及类对象与元类对象之间的关系)?
- OC语言中的消息传递机制是怎样的?
- 缓存查找 (我们进行方法查找的过程当中,如何进行缓存的方法查找?会使用到系统或者说Runtime中一个方法缓存的机制,这个机制又是怎样运行的呢?)
- 消息转发流程是怎样的?
- Method-Swizzling(方法混写)是Runtime的一种运用(我们可以再运行时,去替换一些方法的实现,也得益于动态运行时这一个特性),可能会结合实际的场景,比如说通过时长统计框架这样的考察来了解对于Runtime的Methood-Swizzling技术的一个实际的运用
- 动态添加方法(Runtime提供的功能实现)
- 动态方法解析(Runtime提供的功能实现)
缓存查找流程
我们在缓存查找方法过程当中,实际的问题就是根据给定的方法选择器(SEL),来查找(bucket_t)中对应的方法实现(IMP)
bucket_t是方法选择器和方法实现的封装体,根据SEL去cache_t中找到bucket_t:
- 首先根据给定的方法选择器(SEL),通过一个函数f(key)来映射出对应的bucket_t在数组中的位置
这一步实际是哈希查找,哈希查找实际上是通过我们给定的值, - 经过哈希函数算法key&mask(选择器因子key和对应的一个mask做谓语操作),
算出的值就是给定值在对应数组中的索引位置,提高了查找效率 - 查找到选择器因子(SEL)对应的bucket_t之后,可以提取对应的IMP函数指针,返回给调用方
在当前类中的查找
- 当前类中有对应的方法列表
- 对于已排序好的方法列表,采用二分查找算法查找方法对应的执行函数实现
- 对于没有排序的列表,采用一般遍历去查找方法对应的执行函数实现
ps:二分查找算法:二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。
父类逐级查找
- 通过当前类结构(curClass)的superClass成员变量 去查找(访问)它的父类
把当前类转移到父类之后,需要判断父类是否为nil(NSObject的superClass就是nil),为nil则结束 - 若有父类,则在父类的缓存中查找对应的方法实现,
根据当前方法的选择器因子,在缓存中查到了方法实现,就结束了父类逐级查找流程, - 若在父类缓存中没有查找到方法选择器所对应的方法实现,就需要遍历当前类的父类的方法列表,
来看是否有对应的方法实现,若有则返回,
若没有,继续遍历当前类的父类的父类,一直沿着superClass指针逐级向上查找,
直到NSObject,取父类为nil时,就结束了查找流程
总结
- 缓存是否命中,缓存查找是哈希查找
- 当前类方法列表是否命中,已排序好的是二分查找,未排序好的是一般查找
- 逐级父类方法列表是否命中,根据superClass指针逐级查找父类,在父类中也是先查找缓存,再查找父类