一、底层结构
- 我们可以通过runtime的底层源码看的class的底层结构体,简化如下:
// Class ISA;
isa_t isa; //isa指针
Class superclass;
cache_t cache; //方法缓存cache
class_data_bits_t bits;
}
-
然后点进去之后他们之间的联系如图:
WeChat1634addb04b95eb06580de030bc966ce.png - 由上图中我们的数据结构可知:
- class_rw_t里面的 methods、 properties、protocols 是二维数组,是可读可写的,包含了类的初始内容、分类的内容
- class_ro_t里面的baseMethodList、baseProtocols、ivars、baseProperties是一维数组,是只读的,包含了类的初始内容
二、method_t 是对方法\函数的封装
- 我们经过class_rw_t -> class_ro_t -> method_list_t最终可以找到method_t的结构体, 简化后如下:
struct method_t {
SEL name; // 函数名
const char *types; // 编码(返回值 返回类型)
IMP imp; // 指向函数的指针(函数地址)
}
-
IMP代表函数的具体实现
图片.png - SEL代表方法名\函数名,一般叫选择器,底层结构跟char*类似
- 可以通过@selector()和sel_registerName()获得
- 可以通过sel_getName()和NSStringFromSelector()转成字符串
- 不同类中相同名字的方法,所对应的方法选择器是相同的
-
types包含了函数返回值,参数编码的字符串
图片.png
三、方法缓存:
-
Class内部结构中有个方法缓存(cache_t),用散列表(哈希表 )来缓存曾经调用过的方法,这样可以提高方法的查找速度
图片.png - 缓存查找 = selector(方法名)为_key&_mask 获取到对应的_imp
- objc-cache.mm
- bucket_t * cache_t::find(cache_key_t k, id receiver)
四、方法查找:
-
我们知道实例对象的isa指向类对象,指向类对象的isa类对象,类对象的isa指向元类对象如图:
图片.png 最后其实属性列表,协议列表都是类似的结构和方法查找;