Class內部結構中有個方法緩存(catch_t),用散列表來緩存曾經調用過的方法云挟,可以提高方法的查找速度磅摹。
struct objc_class : objc_object {
Class isa;
Class superclass;
cache_t cache; // 方法緩存
class_data_bits_t bits; // 使用共用體存儲類的信息 &FAST_DATA_MASK 獲得class_rw_t結構
}
class_ro_t和class_rw_t的區(qū)別
class_ro_t存儲了當前類在編譯期就已經確定的屬性信认、方法以及遵循的協(xié)議惧磺,里面是沒有分類的方法的,是只讀的不能修改渣淤。
struct class_ro_t {
method_list_t * baseMethodList; //方法列表(一維數(shù)組)
protocol_list_t * baseProtocols;//協(xié)議列表(一維數(shù)組)
const ivar_list_t * ivars; //成員變量列表
property_list_t *baseProperties; // 屬性列表(一維數(shù)組)
};
class_rw_t是在runtime時才確定,它會先將class_ro_t的內容拷貝過去叛买,然后再將當前類的分類的這些屬性砂代、方法等拷貝到其,所以可以說class_rw_t是class_ro_t的超集率挣。
struct class_rw_t {
//指向只讀的結構體刻伊,存放類初始信息
const class_ro_t *ro;
/*
這三個都是二維數(shù)組,是可讀可寫的椒功,包含了類的初始信息捶箱、分類的信息
methods數(shù)組中存儲著method_list_t 數(shù)組
method_list_t數(shù)組 中存儲著method_t
runtime會將class_ro_t 中的類初始信息合并到這三個數(shù)組中
*/
method_array_t methods; //方法列表(二維數(shù)組)
property_array_t properties;;//屬性列表(二維數(shù)組)
protocol_array_t protocols;// 協(xié)議列表(二維數(shù)組)
}
method_t是對方法/函數(shù)的封裝。
struct method_t {
SEL name; //函數(shù)名 不同類中相同名字的方法动漾,所對應的方法選擇器是相同的丁屎。
const char *types; //編碼(包括返回值類型,參數(shù)類型)
IMP imp; //指向函數(shù)的指針
};
cache_t 方法緩存
struct cache_t {
struct bucket_t *_buckets; //散列表
mask_t _mask; //散列表的長度 - 1 作用:和SEL進行&操作,得到散列表的下標旱眯,存儲方法
mask_t _occupied; //已經緩存的方法數(shù)量 作用: 用于cache_t擴容的判斷
}
struct bucket_t {
cache_key_t _key; //SEL做為key
IMP _imp; //函數(shù)的內存地址
}
查看緩存
編寫Object的底層C++結構體代碼
#import <Foundation/Foundation.h>
#ifndef ClassInfo_h
#define ClassInfo_h
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL //用于取出isa所表示class 晨川、meta_class 的地址
# elif __x86_64__ //模擬器或Mac電腦
# 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__
#define CACHE_END_MARKER 1
static inline mask_t cache_next(mask_t i, mask_t mask) {
return (i+1) & mask;
}
#elif __arm64__
#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; // 協(xié)議列表
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 lc_objc_object {
void *isa;
};
/* 類對象 */
struct lc_objc_class : lc_objc_object {
Class superclass;
cache_t cache;
class_data_bits_t bits;
public:
class_rw_t* data() {
return bits.data();
}
lc_objc_class* metaClass() {
return (lc_objc_class *)((long long)isa & ISA_MASK);
}
};
#endif /* ClassInfo_h */
創(chuàng)建項目并把Object的C++代碼導入項目。
#import <Foundation/Foundation.h>
#import "ClassInfo.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
lc_objc_class *personClass = (__bridge lc_objc_class *)[Person class];
[person personTest];
cache_t cache = personClass->cache;
bucket_t *buckets = cache._buckets;
NSLog(@"%d %d",cache._mask,cache._occupied);
for (int i = 0; i <= cache._mask; i++) {
bucket_t bucket = buckets[i];
NSLog(@"%s %p", bucket._key, bucket._imp);
}
NSLog(@"-----------");
}
return 0;
}
打印如下
2021-09-26 20:27:15.416361+0800 Interview01-cache[35703:1646916] init 0x7ffe2041bc45
2021-09-26 20:27:29.823632+0800 Interview01-cache[35703:1646916] personTest 0x7e78
在控制臺中就可以看到緩存列表中緩存的方法删豺,在調用personTest前共虑,方法緩存列表中只有init方法,在調用personTest后呀页,personTest方法就會存儲到方法列表中妈拌,方便下次快速調用。