类的结构探索

197 阅读2分钟

准备工作

首先我们创建一个继承于NSObject的CFPerson类,在mian 函数初始化,再加一个断点

#import "CFPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...

        CFPerson *person = [CFPerson alloc];

        NSLog(@"Hello, World!  %@",person);
    }
    return 0;
}

接下来看看打印信息

当前类信息

p/x 0x0000000100002150 拿到元类

**元类&**0x0000000ffffffff8ULL打印出得到一个地址

在打印元类的指向,可得到内存信息

po 0x00000001003340f0得到NSObject类

以上打印可分析拟草一个类对象执行过程指向图:

我们再来验证一下:

打印结果发现0x0000000100334140地址不一样,并不是NSObject类,那么它可能会是什么呢?可能是第二个NSObject类。

我们知道类的信息在内存里永远只存在一份。

分析类对象内存存在个数

贴上代码

void cfTestClassNum(){
    Class class1 = [CFPerson class];
    Class class2 = [CFPerson alloc].class;
    Class class3 = object_getClass([CFPerson alloc]);
    Class class4 = [CFPerson alloc].class;
    NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
}

看下打印结果:

可以看出类对象地址都一样,因此类的信息在内存里永远只存在一份

怎样拿到元类?

首先打印当前地址拿到当前iso,通过当前的iso&ISA_MASK 0x0000000ffffffff8ULL,变可得到一个地址0x00000001003340f0,于之前po打印的NSObject地址0x00000001003340f0相等,因此它并不是NSObject类,而是NSObject元类(根元类)

此刻已经到了根元类,再往下走

继续打印当前地址iso信息便会得到根元类的iso,拿到根元类iso再&ISA_MASK 0x0000000ffffffff8ULL得到地址0x00000001003340f0,再再打印其内存情况。

此刻我们发现其内存地址信息与之前的一样,这便意味着NSObject根元类还是指向NSObject根元类,即指自己,那么之前拟草的类对象执行过程指向图得更新一下了:

对于NSObject没有元类的指向,其余定义的类都满足实例对象Instance of Superclass[class]——>当前类Subclass[class]——>当前元类Superclass[class]