iOS类的底层探索(上)

166 阅读3分钟

我们知道,Class的本质是一个结构体objc_class,而这个结构体又继承自objc_object,所以可以说,类本身也是一个对象,它也有isa指针,那么类的isa指向什么地方呢?我们来探索一下。

isa

创建一个XXPerson对象:

图片.png

看打印:

图片.png

通过上面操作,我们看到,类的isa指向了一个同名的类,这两个类的地址不同,所指向的类,是系统自动创建的,叫做元类。 所以,对象isa->类,类isa->元类,类本身也是一个对象

那么,元类的isa又指向什么地方呢?继续探索。

图片.png

我们发现元类的isa指向的是一个NSObject的类,但是它和我们熟悉的NSObject不是同一个地址,我们称其为根元类。又发现,NSObject的isa指向的也是这个根元类

那么,根元类的isa又指向何处呢?

图片.png

可见,根元类的isa指向的是它自己

superclass

了解了元类的isa之后,我们来看下元类的父类。

这里有两个类,XXTeacher和XXPerson,XXTeacher是XXPerson的子类,XXPerson是NSObject的子类。

图片.png

运行结果如下:

图片.png

对比打印的地址,我们可以得出这样一个结论: 子类的元类的父类就是其父类的元类。

结合上面讲到的isa,我们有下图这样的结论:

图片.png

结构体objc_class

图片.png

我们先看下bits里面有啥,其中isa指针占8个字节,superclass占8个字节,cache占16个字节,所以要想获取bits的信息,要将类的地址平移32个字节即可。

图片.png

通过操作,我们获得了一个class_data_bits_t的信息,但是bits = 4308618804是啥意思呢?看不太懂,那就看看class_data_bits_t里面有啥。

class_data_bits_t里面有个data()方法,返回一个class_rw_t结构体,这个class_rw_t里包含类对象的实例方法、协议等信息。

图片.png

图片.png

又看不懂了,咋办?我们看到class_rw_t结构体里有methods()、properties()、protocols()这些方法,这应该就是实例对象的方法、属性和协议吧!

我们试一下methods()!

图片.png

走到这里,我们看到一个count=9,这个count表示的就是这个类的实例方法的数量

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) double height;
@property (nonatomic, assign) short gender;

XXPerson类有4个属性,对应的getter和setter方法,共计8个,未添加其它实例方法,那还有一个方法是什么呢?我们尝试把这9个方法都打印出来!

methods()返回的是一个method_array_t类的对象,method_array_t继承自list_array_tt。

看上图,我们得到的$8是一个method_list_t结构体,其继承自entsize_list_tt。entsize_list_tt可以理解成是一个模板,它可以实例化mothed_list_t、property_list_t等。其下有个get(uint32_t i)方法,试一下!

图片.png

发现并未获取到什么,但是返回的是一个method_t类型的。method_t里面有个big结构体,里面包含SELIMP,这不正是我们想要的吗!!!

struct big {
    SEL name;
    const char *types;
    MethodListIMP imp;
};

试一下:

图片.png 成功!

注意:这里说明一下,因为我的mac的处理器是Intel的,所以这里可以用big方法,如果电脑是m1的,就不能使用big了。关于这点后续我再补充!

通过修改get方法的参数打印出了所有的9个方法,从而确定之前说的多出来的那个方法是".cxx_destruct",这个方法是在ARC下用来释放成员变量的。

图片.png

我们可以用同样的方式来获取属性,按照获取实例方法的步骤,将methods()改成调properties()方法,最后get方法可以直接获取到属性。

图片.png

总结,本文主要介绍了类和元类的isa指向,以及元类之间的父子关系等,那张isa和superclass的综合关系图可以牢记于心。此外,还介绍了类中的bits信息,其中包含如何获取类的实例方法和属性。关于类的其它信息,后续再慢慢补充!