isa、superclass指针验证
验证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,如下图所示:
在Mac下的掩码是 0x00007ffffffffff8ULL ,我们拿到isa来与上这个掩码(相当于拿到的就是person的类对象),我们直接p/x(以16进制打印)这个得到的结果,得到一个新的地址。这个地址,就是类对象的地址。
然后po这个地址,得到Person。结果如下所示
此时我们再次x/4gx刚才得到的类信息的地址,得到他的内容,然后p/x 所得内容的第一个字节(类对象的isa)与上掩码(相当于通过isa指针拿到了类对象指向的元类对象)。然后po这个地址。得到的结果还是Person(不过此时是元类对象)。结果如下图所示:
重复上述的操作(x/4gx、p/x 第一个字节的内容&掩码、po),会发现得到NSObject(相当于,用Person的元类对象的isa 与上 掩码,得到的是NSObject的元类对象,打印出来就是NSObject),结果如下图所示
再重复一次,依然得到的是NSObject(相当于,用NSObject元类对象的isa 与上 掩码,得到的是NSObject元类对象的isa所指向的对象,依然是NSObject)。结果如下图所示。
再重复一次,依然还是得到NSObject。且里面存储的内容已经完全一致(证明了NSObject的元类对象的isa是指向自身的)。
使用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。完美的验证了那副图片。我自己的打印如下图所示。
如果验证元类对象,也是上面的流程,在此不再赘述。
转载自:https://juejin.cn/post/7013261569706426375