Objective-C底层方法查找,会优先从缓存列表查找,那么runtime底层,是如何保存缓存结构的呢?
cache_t结构体图片截取自objc-754版本,objc-runtime-new.h
1、struct bucket_t *_buckets; //数组
bucket_t结构体其中:
SEL _sel; //@selector(),方法名字
uintptr_t _imp; //函数地址
2、mask_t _mask; //总槽位-1
3、mask_t _occupied; //实际使用槽位
其中:typedef uint32_t mask_t; //mask_t 定义
如何进行sel与imp的映射,是能否通过sel找到imp的关键,看cache_t图,第104行
struct bucket_t *find(SEL sel, id receiver);
find函数实现sel名称传入后,使用cache_hash函数发生映射关系 key&mask = index
key是传入的方法名 即:@selector(方法名)
mask是 总槽位-1
Hash表的原理其实是: f(key)=index。通过函数直接找到index
说明:
1、因为hash会发生碰撞 即:@selector(test) & _mask 与 @selector(test1) & _mask 值相同
Apple是如何进行解决的呢?
看do ... while ... 循环,while分支:
while ((i =cache_next(i, m)) != begin);
cache_next函数当发生碰撞时,索引会+1,查找下一个
2、槽位不够时cache如何进行扩容
cache_t expand代码544行,可知:当槽位不够时,会变为原来的2倍
总之,每个objc_class理会有一个cache方法缓存,cache本质上时一个hash表,通过@selector(方法名)&mask 直接找到index,然后找到对应的IMP;当hash发生碰撞时索引会+1;当槽位不够,mask会变为原来的2倍,且在扩展槽位的时候,会清空数组原有的缓存内容;
网友评论