isa详解
- 要想学习Runtime,首先要了解它底层的一些常用数据结构,比如isa指针
- 在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址
- 从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息,具体结构如下
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
struct {
ISA_BITFIELD;
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33;
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19
};
};
isa详解-位域
- 位域(又叫做位段)其实是一种数据结构,可以把数据以位的形式紧凑的储存,并允许程序员对此结构的位进行操作。有些信息在存储的时候,并不需要占用一个完整字节,有时候只需要占用一个或几个二进制位,比如存放一个BOOL类型的变量时,只需要保存0或1两种状态,此时只需要1个二进制位就能存储。因此,位域就是运用在这种场景下的一种数据结构,使用位域可以有效的节省存储空间。
- 位域可以把一个字节中的二进制位划分为几个不同的区域,并且制定每个区域占用的位数,每个域可以设置一个域名,可以根据域名对指定的位进行操作。
- 但是位域也有明显的缺点,就是它的内存分配和内存对齐的方式依赖于具体的机器和操作系统,不同的平台可能会有不同的结果。
- 位域的结构和结构体类似,它的形式为
struct 位域结构名称{
类型说明符 位域名 : 位域长度;
类型说明符 位域名 : 位域长度;
类型说明符 位域名 : 位域长度;
......
}
isa的结构
- isa_t作为共用体,内部使用8个字节的内存空间,共64位二进制位,存放了以下信息:
- nonpointer(1位)
0,代表普通的指针,存储着Class、Meta-Class对象的内存地址
1,代表优化过,使用位域存储更多的信息
- has_assoc(1位)
是否有设置过关联对象,如果没有,释放时会更快
- has_cxx_dtor(1位)
是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
- shiftcls(33位)
存储着Class、Meta-Class对象的内存地址信息
- magic(6位)
用于在调试时分辨对象是否未完成初始化
- weakly_referenced(1位)
是否有被弱引用指向过,如果没有,释放时会更快
- deallocating(1位)
对象是否正在释放
- extra_rc(1位)
里面存储的值是引用计数器减1
- has_sidetable_rc(19位)
引用计数器是否过大无法存储在isa中
如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
class的结构
- 用一张图来展示就是:

class-rw-t
- class_rw_t里面的methods、properties、protocols是二维数组,是可读可写的,包含了类的初始内容、分类的内容

class-ro-t
- class_ro_t里面的baseMethodList、baseProtocols、ivars、baseProperties是一维数组,是只读的,包含了类的初始内容

method_t
struct method_t {
SEL name;
const char *types;
MethodListIMP imp;
}
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
- SEL代表方法\函数名,一般叫做选择器,底层结构跟char *类似
可以通过@selector()和sel_registerName()获得
可以通过sel_getName()和NSStringFromSelector()转成字符串
不同类中相同名字的方法,所对应的方法选择器是相同的
typedef struct objc_selector *SEL;
- types包含了函数返回值、参数编码的字符串

Type Encoding
- iOS中提供了一个叫做@encode的指令,可以将具体的类型表示成字符串编码.
| code | meaning |
|---|
| c | char |
| i | int |
| s | short |
| l | long |
| q | long long |
| c | unsigned char |
| I | unsigned int |
| S | unsigned short |
| L | unsigned long |
| Q | unsigned long long |
| f | float |
| d | double |
| B | C++ bool or C99 _Bool |
| v | void |
| * | A character string(char *) |
| @ | An object(whether statically typed or typed id) |
| # | class object(Class) |
| : | method selecter(SEL) |
| [array type] | An Array |
| {name=type...} | A structure |
| {name=type...} | A union |
| bnum | A bit field of num bits |
| ^type | A pointer to type |
| ? | An unknown type |
方法缓存cache_t
- Class内部结构中有个方法缓存(cache_t),用散列表(哈希表)来缓存曾经调用过的方法,可以提高方法的查找速度

- 缓存查找
objc-cache.mm
struct bucket_t *cache_t::buckets()