美文网首页
底层原理:isa和superclass

底层原理:isa和superclass

作者: 飘摇的水草 | 来源:发表于2022-02-27 10:20 被阅读0次

OC的每个对象中都会有一个isa指针,每个类中都会有一个superclass指针,那么它们有什么用?实例对象,类对象,元类对象之间又有什么联系呢?

isa指针
  1. 对象的isa 指向哪里?

首先我们准备一个继承自NSObject的JJPerson类,定义一个对象方法和一个类方法,然后我们分别调用这两个方法。

类方法实际在元类对象中而不是类中,对象方法实际存放在类对象中而不是实例对象中,那它们分别是怎么调用到并没有存放在自身的东西呢?这时候就是isa指针发挥作用了。

如上图所示:

  • instance的isa指向class
    • 当调用对象方法时,通过instance的isa找到class,最后找到对象方法的实现进行调用
  • class的isa指向meta-class
    • 当调用类方法时;通过class的isa找到meta-ciass,最后找到类方法的实现进行调用
class对象的superclass指针

我们把问题变得稍微复杂一些,我们为JJPerson增加一个子类JJStudent,同样顺手为它准备一个对象方法和一个类方法。

正如我们所知,student继承自person,它是可以调用父类的方法的。

但是Person的对象方法和类方法都是存放在Person的类对象和元类对象中,Student的类和实例对象是怎么调用它们的呢?这样的情况下isa指针看起来已经不能满足我们的需求了,那这时候就需要superclass指针。

  • 当Student的instance对象要调用Person的对象方法时,会先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用
  • 当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用
isa和superclass总结

这张经典的图相信很多iOS开发者都看过,它很好地指出了isa和superclass在OC对象之间所担任的联系

综合我们上面提到的例子,我们可以为这张图加上备注方便理解

总结如下:

  • instance的isa指向class

  • class的isa指向meta-class

  • meta-class的isa指向基类的meta-class

  • class的superclass指向父类的class

  • 如果没有父类,superclass指针为nil

  • meta-class的superclass指向父类的meta-class

  • 基类的meta-class的superclass指向基类的class

  • instance调用对象方法的轨迹

    • isa找到class,方法不存在,就通过superclass找父类
  • class调用类方法的轨迹

    • isa找meta-class,方法不存在,就通过superclass找父类
isa细节

前面我们提到,在OC对象中实例对象的isa是指向类对象,类对象的isa指向元类对象,这样我们可以通过isa把OC中的三种对象联系起来。那么,isa是怎么实现的呢?实例对象的isa直接存放着类对象的地址,类对象的isa直接存放元类对象的地址吗?


  • 首先我们准备一个JJPerson继承自NSObject,分别拿到它的实例对象,类对象和元类对象,并分别打印它们的地址值
  • 我们先通过打印拿到person的isa地址和person的类对象地址,通过对比我们发现,其实他们是并不相等的
  • person->isa:0x001d8001000011d1
  • personClass:0x00000001000011d0

在控制台可以通过以下命令来查看对象的isa指针:

(1ldb) p person–>isa
(Class) $0 = MJPerson

如果想要看isa的地址值可以通过强转的方式:

(1ldb) p (long)person->isa
(1ong) S1 = 8303516187936969

这样输出的地址值是十进制的,通过下面命令可以输出十六进制的地址值:

(11db) p/x (long)person->isa
(1ong) S2 = 8x801d8001000014c9

那么实例对象是怎么通过isa来找到类对象的呢?这里就不得不提一个ISA_MASK的东西,我们还是从源码寻找答案。

分析

  • 其实从64bit开始,isa需要进行一次位运算,才能计算出真实地址,这个位运算的对象就是ISA_MASK
  • ISA_MASK的值不是唯一的,在arm64和X86架构下是不同的
  • 有了ISA_MASK后我们可以看到看到,person的isa通过和ISA_MASK进行一次位运算后,得出的值就是我们JJPerson类对象在内存中的值。同理类对象和元类对象我们也可以去证明。不过我们直接尝试去获取类对象的isa时,会发现并不能直接获取到,因为Xcode提示说它并不认为这是一个结构体
  • 但是我们点击Class进去,再点击进入它的objc_class里面可以看到,它是确实存在isa的,但是只是没有暴露给我们而已

其实这个问题不难解决,因为我们可以看到objc_class的结构,那么我们可以定义一个和它一样的结构体来获取isa

  • 为了避免明明冲突,我们定义一个jj_objc_class结构体,和objc_class一样,它里面也有一个Class类型的isa
  • 在30行代码处,我们通过自定义的结构体去获取JJPerson的类对象
  • 通过打印我们可以发现,我们新获取JJPerson的类对象isa通过和ISA_MASK进行位运算后,得出的地址正是我们JJPerson元类对象的地址

这也证明了,我们OC对象中的isa并不是直接存放所指向对象的地址值,而是需要通过和ISA_MASK进行一次位运算才能得出真实地址。

  • 以前对象的isa指针是直接指向类对象的,但是从64bit开始,isa需要进行一次位运算,才能计算出真实地址,位运算是& ISA_MASK
  • 子类的类对象super class指针是直接指向父类的类对象的,不存在& ISA_MASK

相关文章

网友评论

      本文标题:底层原理:isa和superclass

      本文链接:https://www.haomeiwen.com/subject/ynfhrrtx.html