iOS方法缓存-散列表

Class 内部结构中有个方法缓存( cache_t ), 用散列表来缓存曾经调用过的方法,可以提高方法的查找速度

每个类都有一个自己的方法列表数组,每次调用方法的时候,都会去找当前的类的方法数组看看有没有这个方法,如果没找到,就去父类寻找,不过,在这些之前,最先去缓存数组cache 里面找,如果是第一次调用,在方法列表里面找到这个方法之后,会把这个方法在父类和当前累的缓存数组里面各保存· 一份

当数组已经装不下的时候,数组就会翻倍扩容,然后把之前的数据清空

怎么存储缓存的方法:散列表技术 key-value

cache_t 的数据结构

思路 :调用方法的时候,通过方法名(key)去到通过isa指针找到的对应的类的缓存数组里面的散列表( struct _bucket_t *_buckets )查找,如果找到,直接拿出对应的函数内存地址。直接调用(这就是为啥一个类里面不能有相同名称的方法)

#import <objc/runtime.h>

#import <objc/message.h>

NSLog(@"%p",@selector(test)); // 输出方法的内存地址

objc_msgSend(person, @selector(test)); // 调用person类的test方法

散列表的数据储存位置:

@selector(personTest) @ _mask( 散列表的长度-1 ) = 这个数据缓存的位置的下标,也就是缓存方法的索引,这个下标经过位运算之后,一定会小于或者等于散列表的长度-1 ,就不会出现数组越界的情况了

散列表数据结构

打印缓存的方法

Student *student = [[Student alloc]init];

mj_objc_class *studentClass = (__bridge mj_objc_class *)[Student class];

[student studentTest];

[student personTest];

[student studentTest];

[student personTest];

cache_t cache = studentClass->cache; // 拿到缓存cache

bucket_t *buckets = cache._buckets; // 里面是通过散列表的思路进行缓存的

// mj的获取方法

// NSLog(@"%s %p",@selector(studentTest), cache.imp(@selector(studentTest)));

// bucket_t bucket = buckets[(long long)@selector(personTest) & cache._mask ];

// NSLog(@"------------");

// NSLog(@"%s %p",bucket._key, bucket._imp);

// NSLog(@"------------");

// 打印全部缓存数据

for (int i = 0 ; i <= cache._mask ; i++) {

bucket_t bucket = buckets[i];

NSLog(@"%s %p",bucket._key, bucket._imp);

}

// 直接通过 索引去除对应的bucket

// 1、 算出索引 @selector(personTest) & _mask

bucket_t bucket = buckets[(long long)@selector(studentTest) & cache._mask ];

NSLog(@"%s %p",bucket._key, bucket._imp);

最后:

感谢 MJ 老师的视频教程,受益良多,有兴趣的同学可以了解一下,MJ 底层原理开发,腾讯视频就有,为了避免说我打广告,链接我就不发了

猜你喜欢

转载自blog.csdn.net/s12117719679/article/details/82887982