likes
comments
collection
share

isa、superclass指针验证

作者站长头像
站长
· 阅读数 35

验证isa

上个博客,我们引入了isa、类对象、元类 对象。介绍了他们之间的关系。今天我们来稍微的验证一下。

新建一个简单快捷的MacOC工程,当然iOS的工程也可以。 是定义一个Person类,继承自NSObject。不需要有啥属性,有这个类就行。 接下来定义一个Student类,继承自Person,同样不需要有啥属性,有这个类就行。 我们在main.m里用这两个类创建对象。代码很简单,如下:

然后我们在NSLog这一行打个断点。运行程序。接下来我们重复下面三个步骤:

第一步:x/4gx:打印对象地址的存储的内容,共四个字节。第一个字节的内容就是isa指针。 第二步:p/x:打印第一步中的第一个字节的内容 & 掩码 。就是isa & 掩码。 第三步:po 第二步得到的结果。

按照我们上一篇中的总结,person这个实例对象的isa指针,是指向PerSon类对象的。我们先来打印一下x/4gx person(x/4gx,以16进制打印内存里的内容,4gx表示读取4个字节,每个字节以16进制表示)。此时拿到person这个地址实际存储的内容,第一个8字节存储的就是isa,如下图所示:

isa、superclass指针验证

在Mac下的掩码是 0x00007ffffffffff8ULL ,我们拿到isa来与上这个掩码(相当于拿到的就是person的类对象),我们直接p/x(以16进制打印)这个得到的结果,得到一个新的地址。这个地址,就是类对象的地址。 isa、superclass指针验证 然后po这个地址,得到Person。结果如下所示

isa、superclass指针验证

此时我们再次x/4gx刚才得到的类信息的地址,得到他的内容,然后p/x 所得内容的第一个字节(类对象的isa)与上掩码(相当于通过isa指针拿到了类对象指向的元类对象)。然后po这个地址。得到的结果还是Person(不过此时是元类对象)。结果如下图所示:

isa、superclass指针验证

重复上述的操作(x/4gx、p/x 第一个字节的内容&掩码、po),会发现得到NSObject(相当于,用Person的元类对象的isa 与上 掩码,得到的是NSObject的元类对象,打印出来就是NSObject),结果如下图所示

isa、superclass指针验证

再重复一次,依然得到的是NSObject(相当于,用NSObject元类对象的isa 与上 掩码,得到的是NSObject元类对象的isa所指向的对象,依然是NSObject)。结果如下图所示。

isa、superclass指针验证

再重复一次,依然还是得到NSObject。且里面存储的内容已经完全一致(证明了NSObject的元类对象的isa是指向自身的)。

isa、superclass指针验证

使用student的打印,也是同样的过程,在此就不再演示。

验证superclass

关于继承关系,我们也说到了,类对象和元类对象是有superClass指针来实现了类对象和元类对象的继承关系的,再次补充一下,继承关系只存在于类对象和元类对象,实例对象是没有继承关系的。

在这,我们补充一下,Class这个东西。在苹果的源码中,我们找到关于Class的定义,是继承自objc_object的结构体。源码如下 :

typedef struct objc_class *Class;
//objc_class 是继承自objc_object的结构体

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const {
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

    void setInfo(uint32_t set) {
        ASSERT(isFuture()  ||  isRealized());
        data()->setFlags(set);
    }

    void clearInfo(uint32_t clear) {
        ASSERT(isFuture()  ||  isRealized());
        data()->clearFlags(clear);
    }

    // set and clear must not overlap
    void changeInfo(uint32_t set, uint32_t clear) {
        ASSERT(isFuture()  ||  isRealized());
        ASSERT((set & clear) == 0);
        data()->changeFlags(set, clear);
    }

#if FAST_HAS_DEFAULT_RR
    bool hasCustomRR() const {
        return !bits.getBit(FAST_HAS_DEFAULT_RR);
    }
    void setHasDefaultRR() {
        bits.setBits(FAST_HAS_DEFAULT_RR);
    }
    void setHasCustomRR() {
        bits.clearBits(FAST_HAS_DEFAULT_RR);
    }
#else
    bool hasCustomRR() const {
        return !(bits.data()->flags & RW_HAS_DEFAULT_RR);
    }
    void setHasDefaultRR() {
        bits.data()->setFlags(RW_HAS_DEFAULT_RR);
    }
    void setHasCustomRR() {
        bits.data()->clearFlags(RW_HAS_DEFAULT_RR);
    }
#endif
 ……
//下面还有很多代码,没有完整的粘贴过来
//这段代码来自 objc4-787.2.tar.gz 中objc-runtime-new.h文件  1244行

在上一篇中,我们知道的了objc_objcet里有一个isa指针的,所以,objc_class(Class)也就有了isa,且存在于第一个字节中。接下来就是superclass指针,这个superclass指针也是Class类型的。我们开验证一下superclass指针。跟上面验证isa是一样的,我们在同样的工程上验证。 同样,我们先用x/4gx来读取person的内存内容,p/x然后再用第一个isa与上掩码,找到他的类对象。x/4gx这个元类对象。此时,我们读取出了元类对象内存内容。按照我们的总结,此时第二个字节存储的是父类的信息,我们使用po命令,也就是以对象的形式打印第二个字节。得到的是NSObject。验证了Person是继承自NSObject的。我们在以同样的流程验证student。发现可以找到Person/NSobject。到NSObject,此时的打印superclass会是nil。完美的验证了那副图片。我自己的打印如下图所示。

isa、superclass指针验证

如果验证元类对象,也是上面的流程,在此不再赘述。

转载自:https://juejin.cn/post/7013261569706426375
评论
请登录