isa
在哪里有以下代码,在控制台输出obj
的数据结构,排在第一位的就是isa
的地址。 数据结构
为何呢?由于对象继承自NSObject
,NSObject
在底层的实现是结构体objc_object
,里面只有一个isa
成员变量,那么对象的首地址指向的第一块就是isa
所在。架构
isa
的类型正常来讲isa
指向的就是该对象的类,那咱们打印这个地址应该输出类名,可是出乎意料的是这里并无打印出类名。 ide
去源码里面找找看,发现isa
是Class
类型函数
Class
类型实际上是objc_class
post
能够看到objc_class
继承自objc_object
,那么里面就应该有一个isa
。此外还有的成员变量就是superclass
、cache
、bits
、data
。 优化
isa
的结构可是不行,这样也看不出来什么呀,仍是不知道isa
究竟是什么。有看过 iOS alloc & init 方法解析 的朋友应该有印象,在alloc
方法里面会调用一个叫initIsa()
的方法,那么是否是能够在这个方法中找到isa
的真正结构呢?3d
终于找到了,原来isa_t
是个联合体,看下来重点就应该在ISA_BITFIELD
指针
喜大普奔终于找到了,注意的咱们要关注arm64
下的结构。前面的是参数名、后面的是所占位数,总数加起来是64位。 调试
参数名 | 做用 | 大小 | 所在位置 |
---|---|---|---|
nonpointer | 是否对isa 指针开启指针优化0:纯 isa 指针只包含类对象地址1: isa 中包含了类对象地址、类信息、对象的引用计数等 |
1 | 0 |
has_assoc | 是否有关联对象 0:没有 1:存在 |
1 | 1 |
has_cxx_dtor | 该对象是否有C++ 或者Objc 的析构器 若是有析构函数则须要作析构逻辑 若是没有则能够更快的释放对象 |
1 | 2 |
shiftcls | 存储类指针的值。开启指针优化的状况下,在arm64 架构中有 33 位用来存储类指针 |
33 | 3~35 |
magic | 用于调试器判断当前对象是真的对象仍是没有初始化的空间 | 5 | 36~40 |
weakly_referenced | 是否有弱引用 0:没有 1:存在 |
1 | 41 |
deallocating | 是否正在释放内存 0:不是 1:是 |
1 | 42 |
has_sidetable_rc | 是否须要用到外挂引用计数,当对象引用技术大于 10 则须要借用该变量存储进位 | 1 | 43 |
extra_rc | 该对象的引用计数值,其实是引用计数值减 1。 若是对象的引用计数为10,那么 extra_rc 为 9。若是引用计数大于 10 则须要使用 has_sidetable_rc |
19 | 44~63 |
那么咱们知道了,在开启isa优化
的时候对象的指针是存在isa
的shiftcls
里面,那么怎么得到shiftcls
呢?咱们强转isa
的类型为isa_t
后打印code
isa
获取类shiftcls
是有了,可是这里面还不是类?这时候咱们再来看shiftcls
是怎么来的。
原来是cls
右移3位。那么咱们把它还原一下,成功~
日常获取对象的类会直接调用class
方法,那么class
方法内部实现是怎样的?
重点来了,getIsa()
方法;
当前不是taggedPointer,直接返回ISA()
ISA()
里面根据判断条件就会走到最后的一行,就是isa.bits
和ISA_MASK
作一下与运算
咱们来看看ISA_MASK
ISA_MASK
有了,可是isa.bits
怎么获取呢??这里打印isa
出来的数值和结构里bits
的值如出一辙!
那么咱们尝试一下~把isa
打印的值和ISA_MASK
与运算~成功获取到类
ISA
的指向这个时候已经验证了能够经过对象的isa
获取到对象的类,那么类自己也是一个对象,它的isa
又是指向那里呢?
LGPerson
,第一层是咱们的对象,第二层是类对象。第三层虽然也是LGPerson
,可是地址和第二层的不同,说明不是同一个对象。类对象在内存中是只能存在一个的,那么第三层确定就是元类了。isa
指向的是NSObject
,NSObject
的象isa
指向的也是NSObject
。看看2个NSObject
的地址是相同的,因此NSObject
的isa
是指向了自身,也就是NSObject
和LGPerson
具备同一个根元类。
那么咱们能够获得四个结论
isa
指向其类isa
指向其元类isa
指向根元类isa
都指向根元类