1.runtime的作用
OC是一个动态性较强的语言,其动态的本身就是因为runtime,把编译过程中的某些东西放到运行时来做
所以runtime的作用:
1.动态的创建类,比如KVO的新类就是运行的时候创建的
2.访问已有类的各种属性/方法,比如JSON转Model
3.修改或者添加成员属性和方法
4.消息机制,消息转发 实际应用少,但面试贼多,可以处理找不到函数产生的闪退
2.runtime的底层架构
runtime的本质就是操作isa superClass这些指针去访问
isa取值的问题
isa从64位系统开始,引入了位域和共用体的
比如0x 01101010 取出它的第二位
用. 0x 00000010去&上它就好了
int a = 0b00001101;
int b = 0b00000010;
int c = 0b00000100;
printf("%d",a & b); //0 取出第二位,因为第二位是0所以结果是0b000,也就是0
printf("%d",a & c); //4 转换成二进制就是0b100,也是取出了第三位
比如上面代码,用b取出了第二位,用c取出了第三位
再改下:
int a = 0b00001101;
int b = 2;
int c = 4;
printf("%d",a & b); //0 取出第二位,因为第二位是0所以结果是0b000,也就是0
printf("%d",a & c); //4 转换成二进制就是0b100,也是取出了第三位
也是一样的结果,因为0b00000100就是10进制的4,0b00000100就是十进制的2
再补充下位移:
int a = 0b00001101;
int b = 1 << 1; //把1向左移动移移动一位就是0b000010 也就是十进制的2
int c = 1 << 2; //把1向左移动两位就是0b000100 也即使十进制的4
printf("%d",a & b); //0 取出第二位,因为第二位是0所以结果是0b000,也就是0
printf("%d",a & c); //4 转换成二进制就是0b100,也是取出了第三位
上述这种叫位操作,只操作某一位,比如说,某一位只存储bool值,所有位都有一个单独的bool属性,这个就叫位域,目的就是一个值,&上不同的值,来得到多种不同的值,以达到节约空间的目的,Union(共用体)就是这个目的,isa就用了位域和共用体如下
简单了解就好
class的内存结构
不管怎么样,isa还是拿到了类对象的存储地址,
类的内存结构:
大概如上,值得一提的是 ro里面的内容是不能修改的,就是右边的那一块
method_list_t(方法列表)
两种的最终结果都是method_t
也不解释了,注释很清楚,第一个是函数名称,项目常用,我们可以用到的是字符串,C语言输出字符串的方式输出
NSLog(@"%s",@selector(test))
方法缓存列表
cache_t是方法的缓存列表,用散列表存储用过的方法,提高方法的查找速度
所以可以看出这个散列表是个数组,但又有键值对,所以更像是字典
所以散列表肯定也不是遍历整个数组,而是存储地址具有某种规律,用,@selector(test)对应的SEL去&cache_t里面的mask能得到散列表对应的起始值,然后根据这个起始值再进行遍历,是+还是减,要根据架构来,源码区分了x86和x64架构,在objc源码->objc-cache->cache :: find这个函数里面,另外再提一句,苹果里面很多的查找方式都是用的&机制