iOS isa详解

1、isa 在哪里

有以下代码,在控制台输出obj的数据结构,排在第一位的就是isa的地址。 数据结构

为何呢?由于对象继承自NSObjectNSObject在底层的实现是结构体objc_object,里面只有一个isa成员变量,那么对象的首地址指向的第一块就是isa所在。架构

2、isa 的类型

正常来讲isa指向的就是该对象的类,那咱们打印这个地址应该输出类名,可是出乎意料的是这里并无打印出类名。 ide

去源码里面找找看,发现isaClass类型函数

Class类型实际上是objc_class post

能够看到objc_class继承自objc_object,那么里面就应该有一个isa。此外还有的成员变量就是superclasscachebitsdata优化

3、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优化的时候对象的指针是存在isashiftcls里面,那么怎么得到shiftcls呢?咱们强转isa的类型为isa_t后打印code

4、isa 获取类

shiftcls是有了,可是这里面还不是类?这时候咱们再来看shiftcls是怎么来的。

原来是cls右移3位。那么咱们把它还原一下,成功~

5、怎么从对象获取类

日常获取对象的类会直接调用class方法,那么class方法内部实现是怎样的?

重点来了,getIsa()方法;

当前不是taggedPointer,直接返回ISA()

ISA()里面根据判断条件就会走到最后的一行,就是isa.bitsISA_MASK作一下与运算

咱们来看看ISA_MASK

ISA_MASK有了,可是isa.bits怎么获取呢??这里打印isa出来的数值和结构里bits的值如出一辙!

那么咱们尝试一下~把isa打印的值和ISA_MASK与运算~成功获取到类

6、ISA的指向

这个时候已经验证了能够经过对象的isa获取到对象的类,那么类自己也是一个对象,它的isa又是指向那里呢?

  • 简单的多打印几层,咱们看到打印结果有3层是LGPerson,第一层是咱们的对象,第二层是类对象。第三层虽然也是LGPerson,可是地址和第二层的不同,说明不是同一个对象。类对象在内存中是只能存在一个的,那么第三层确定就是元类了。
  • 往上继续打印,发现元类对象isa指向的是NSObjectNSObject的象isa指向的也是NSObject。看看2个NSObject的地址是相同的,因此NSObjectisa是指向了自身,也就是NSObjectLGPerson具备同一个根元类。

那么咱们能够获得四个结论

  • 对象的isa指向其类
  • 类对象的isa指向其元类
  • 元类的isa指向根元类
  • 全部元类的isa都指向根元类

相关文章
相关标签/搜索