每一个类、每一个元类都有一个cache_t对象,cache_t对象是一个结构体,里面有3个成员变量:①存储了你之前调用过的某个类对象或者实例对象的方法(你调用过的类方法会存储在元类的cache_t对象里面,而你调用过的实例方法会存储在类的cache_t对象里面)的哈希表(下图的struct bucket_t *_buckets
),该哈希表只是通过一个数组实现的,解决哈希冲突的方法是线性探测法,而不是拉链法(看接下来的bucket_t * cache_t::find(cache_key_t k, id receiver)
可知该哈希表解决哈希冲突的方法是线性探测法);②哈希表的长度 - 1(下图的mask_t _mask
);③已经缓存的方法数量(下图的mask_t _occupied
)。其中,mask_t
的定义为typedef uint32_t mask_t;
。
在看从方法缓存列表中查找目标方法之前,先看一下哈希表的实现的几种方式,因为上图的find()函数使用的只是哈希表的其中一种实现方式(线性取值法)。
下图是哈希表的实现原理简介,并以线性取值法(解决哈希冲突的一种方式)为例。
bucket_t * cache_t::find(cache_key_t k, id receiver)
的源码如下:
用一个demo验证一个方法调用后会被缓存到方法缓存列表中
demo的目录结构如下:
main.mm(注意:要把main.m改名为main.mm,因为.m文件不支持c++代码)文件代码如下:
#import <Foundation/Foundation.h>
#import "MyClassInfo.h"
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//debug调试Person类的缓存方法列表的个数的变化
Person *person = [Person new];
my_objc_class *personClass = (__bridge my_objc_class*)[Person class];
[person test];
//打印person对象的类的方法缓存列表里面缓存的所有方法
cache_t cache = personClass->cache;
bucket_t *buckets = cache._buckets;
for (int i = 0; i <= cache._mask; i++) {
bucket_t bucket = buckets[i];
NSLog(@"SEL = %s,IMP = %p", bucket._key, bucket._imp);
}
NSLog(@"-------");
}
return 0;
}
MyClassInfo.h文件代码如下:
#import <Foundation/Foundation.h>
#ifndef MyClassInfo_h
#define MyClassInfo_h
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# endif
#if __LP64__
typedef uint32_t mask_t;
#else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;
#if __arm__ || __x86_64__ || __i386__
// objc_msgSend has few registers available.
// Cache scan increments and wraps at special end-marking bucket.
#define CACHE_END_MARKER 1
static inline mask_t cache_next(mask_t i, mask_t mask) {
return (i+1) & mask;
}
#elif __arm64__
// objc_msgSend has lots of registers available.
// Cache scan decrements. No end marker needed.
#define CACHE_END_MARKER 0
static inline mask_t cache_next(mask_t i, mask_t mask) {
return i ? i-1 : mask;
}
#else
#error unknown architecture
#endif
struct bucket_t {
cache_key_t _key;
IMP _imp;
};
struct cache_t {
bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
IMP imp(SEL selector)
{
mask_t begin = _mask & (long long)selector;
mask_t i = begin;
do {
if (_buckets[i]._key == 0 || _buckets[i]._key == (long long)selector) {
return _buckets[i]._imp;
}
} while ((i = cache_next(i, _mask)) != begin);
return NULL;
}
};
struct entsize_list_tt {
uint32_t entsizeAndFlags;
uint32_t count;
};
struct method_t {
SEL name;
const char *types;
IMP imp;
};
struct method_list_t : entsize_list_tt {
method_t first;
};
struct ivar_t {
int32_t *offset;
const char *name;
const char *type;
uint32_t alignment_raw;
uint32_t size;
};
struct ivar_list_t : entsize_list_tt {
ivar_t first;
};
struct property_t {
const char *name;
const char *attributes;
};
struct property_list_t : entsize_list_tt {
property_t first;
};
struct chained_property_list {
chained_property_list *next;
uint32_t count;
property_t list[0];
};
typedef uintptr_t protocol_ref_t;
struct protocol_list_t {
uintptr_t count;
protocol_ref_t list[0];
};
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize; // instance对象占用的内存空间
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name; // 类名
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars; // 成员变量列表
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
};
struct class_rw_t {
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_list_t * methods; // 方法列表
property_list_t *properties; // 属性列表
const protocol_list_t * protocols; // 协议列表
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
};
#define FAST_DATA_MASK 0x00007ffffffffff8UL
struct class_data_bits_t {
uintptr_t bits;
public:
class_rw_t* data() {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
};
/* OC对象 */
struct my_objc_object {
void *isa;
};
/* 类对象 */
struct my_objc_class : my_objc_object {
Class superclass;
cache_t cache;
class_data_bits_t bits;
public:
class_rw_t* data() {
return bits.data();
}
my_objc_class* metaClass() {
return (my_objc_class *)((long long)isa & ISA_MASK);
}
};
#endif /* MyClassInfo_h */
Person类的代码如下:
#import <Foundation/Foundation.h>
@interface Person : NSObject
-(void)test;
@end
//---------分割线,分隔一个类的.h文件和.m文件-------
#import "Person.h"
@implementation Person
-(void)test {
NSLog(@"%s", __func__);
}
@end
运行结果一:
运行结果二
运行结果三