NSObject本质

1:结构

1:NSObject在内存中的大小:

系统分配给NSObject实例对象16个字节,但是对象只用了8个字节.

2:OC 对象分三类:实例对象(instance)、类对象(Class)、元类对象(MetaClass).

instance:存放了isa、成员变量值。

Class:isa,superCalss,cache_t, class_data_bits_t四个成员。

MetaClass:  结构和类对象一致,只是它存的数据比类对象少,存了类对象方法,isa,superClass。其他很多地方都是nil。

2 成员具体内容

1 class_data_bits_t

class_data_bits_t&FAST_DATA_MASK获取的class_rw_t  中存了成员方法列表,属性列表,协议列表,flags,version等一些信息。这三个列表是二维数组(数组的成员是每个类的所有分类的一位数组方法列表,属性列表,协议列表)。

class_ro_t 中也存了方法列表,协议列表, 属性列表。但是这个结构体里的列表都是一维数组,在运行时,会将一个类的所有,分类,协议,属性重新规划,并且class_ro_t是不可读的。具体见 图-01。

2304477-5adac84aba1d4245.png
图-01

值得注意的是class_data_bits_t一开始也是指向class_ro_t,在运行时,合并分类的时候,才将class_data_bits_t指向class_ro_t.

2 isa和superClass与类的关系

实例对象isa指向类对象,类对象isa指向元类对象,所有的元类对象isa指向基类的元类(报括基类的isa,指向自己)。

实例对象没有superClass,类对象superClass指向其父类,基类的superClass指向基类的类对象([NSObject class]).基类的superClass =nil;。

#  define ISA_MASK        0x00007ffffffffff8ULL

这里的isa是指arm64之前的,若是arm64之后,则需要把isa &ISA_MASK,取出其中一段才是我们之前概念里面的isa指针。因为arm64之后,苹果有优化,Class isa 变成了 isa_t这个union公用体,里面不止是存了类对象,元类对象的地址,还存着有其他许多信息,比如nonpointer代表,bits里有一个bit代表这个isa是否是普通指针


2304477-079c6ed045dbeb03.png
图-02

3 cache_t

cache_t:调用过的方法列表。结构体里存着三个成员:struct bucket_t *_buckets//散列表、mask_t _mask;//散列表的长度-1 、ma s k_t  _occupied;//已经缓存的方法数量。_bucket 里存两个成员:cache_key_t key;//SEL作为key   IMP _imp //函数的内存地址。如 图-02:

2304477-b09f6cae36ee9e30.png
图-03

往cache_t里存方法过程:

用方法的SEL(_key),即@selector(方法名)&_mask 得到一个索引,然后看buckets对应索引的位置有没有方法,没有的话,_key = @selector(方法名), _imp = 函数地址组成一个bucket存到对应索引的位置。若是一开始对应索引已经存值了,把索引-1,把bucket存到这里。若是每个索引位置都有bucket存着,则清空 buckets, mask_t乘以2,把bucket存到对应索引位置。

从cache_t里取方法过程:

用方法的SEL(_key),即@selector(方法名)&_mask 得到一个索引,然后根据索引从_buckets散列表里取出一个_bucket,把_bucket里的_key 和 @selector(方法名)对比,若是相等则返回方法,若是不相等则,把索引减1,往前查找,一直查到0,若是还找不到,则跳到最后,一直找到之前索引位置+1.还没有则返回null。

散列表(哈希表):用某种算法获取值当成索引获取value,存取数据,空间换时间。

查找方法过程:

先去一个类的cache_t里去查找,如果找不到则去methods方法列表里去找,找到的话就往cache_t里存,如果找不到,则通过superCalss指针找到它的父类,在父类里的cache_t里找,找不到则去方法列表里找,找到的话,往子类的cache_t里存(注意是自己的cache_t)。再找不到则通过父类的superCalss里去找,一直找到基类或者抛出异常。

class_data_bits_t & FAST_DATA_MASK 可以获得 图-04内容,其中methods是二维数组,存着许多method_list_t(一维数组),每个method_list_t可能是一个分类的所有方法的数组。或者类本身方法数组。method_list_t里存着许多个method_t,里面内容如图-05:


2304477-f331738d0ef15aab.png
图-04


另:method结构

2304477-4742a3eefbfcc02b.png
图-05

属性列表和协议列表与之类似。

注SEl :当作方法名方法序列号,里面首元素为char类型,因为把它的地址转成char就是字符串,结构体地址即是首元素地址。 

内容仅供自己记录学习内容。

转载于:https://www.jianshu.com/p/245609b5190c

猜你喜欢

转载自blog.csdn.net/weixin_33910137/article/details/91166273