runtime简介
运行时(Runtime)是指将数据类型的确定由编译时推迟到了运行时,Runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API,平时编写的OC代码,在程序运行过程中,其实最终会转换成Runtime的C语言代码,Runtime是Object-C的幕后工作者,Object-C会使用到Runtime来创建类和对象,进行消息发送和转发
特性: 编写的代码具有运行时、动态特性
isa
在我们初窥oc对象的时候了解到了isa,开始的时候我们感觉它像是一个C的指针,现在我们想要细致的了解iOS的运行时机制,我们需要更加细致的了解isa,对于我们了解runtime有很大的帮助。
在arm64之前,isa只是一个指针,保存对象地址或者类对象地址,但是在arm64架构之后,苹果对isa进行了优化,变成了一个union结构,通过位域方式来存储更多的信息。
共用体:在进行某些算法的C语言编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体。
先看下objc_object源码
我们知道OC对象的isa指针并不是直接指向类对象或者元类对象,而是需要&ISA_MASK通过位运算才能获取到类对象或者元类对象的地址。今天来探寻一下为什么需要&ISA_MASK才能获取到类对象或者元类对象的地址,以及这样的好处。源码中isa_t是union类型, 可以看到共用体中有一个结构体,结构体内部分别定义了一些变量,变量后面的值代表的是该变量占用多少个二进制位,也就是位域技术。
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;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 8
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
# else
# error unknown architecture for packed isa
# endif
可以简化为下面的图
这里我们了解下每个字段的意义
nonpointer 代表iOS是普通的指针,存储着Class、Meta-Class对象的内存地址代表优化过,使用位域存储更多的信息
has_assoc 是否有设置过关联对象,如果没有,释放时会更快
has_cxx_dtor 是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
shiftcls 存储着Class、Meta-Class对象的内存地址信息
magic 用于在调试时分辨对象是否未完成初始化
weakly_referenced 是否有被弱引用指向过,如果没有,释放时会更快
deallocating 对象是否正在释放
extra_rc 里面存储的值是引用计数器减1
has_sidetable_rc 引用计数器是否过大无法存储在isa中如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
isa需求
isa取值
00000101
&00000100
·-------------
00000100
isa进行&操作,取哪位哪位值为1,结果有值相应位为1无值为0
补充“>>”代表左移 ,例“1>>0”左移0位 0b000001 值位1 ,“1>>1左移1位 0b000010 值位2
isa取值
使用||操作,和&操作
设置位赋值为1
设置位赋值为1,先安位取反 00000100 = ~111101111,在安位&,
取反产操作“~”
00000101
&11111011
·-------------
00000001
isa位域
// 位域技术,利用了每个字节的每一位
struct {
char tall : 1;
char rich : 1;
char handsome : 1;
} _tallRichHandsome; 一个
补充共用体
在进行某些算法的C语言编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,简称共用体,也叫联合体,用isa举例子:isa所有数据都存在bits里面,下面的结构体是用于理解的