上一篇类的原理(上)中我们探索了类的属性以及对象方法的存储位置,但是我们在探索过程中并没有找到成员变量和类方法的存储位置,那么这篇文章我们一起探索下成员变量和类方法的存储位置。
成员变量
1、我们通过上篇分析后没有找到成员以及类方法的存储位置,所以我们继续到class_rw_t
结构体去分析,最后找到如下函数:
2、那么我们再去使用源码+lldb
去调式一下看看,这个里面存储的是什么呢?
3、从上图打印结果我们可以看到,在class_rw_t
结构体中的ro()
方法回调能够得到一个class_ro_t
结构体,这个结构体的内容比较多,但是经过简化我们需要的后,大概如下:
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
union {
const uint8_t * ivarLayout;
Class nonMetaclass;
};
void *baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
}
以上就是我们需要的一些基本的成员,能够得到我们想要的成员变量列表、方法列表,协议列表,属性列表等等。
4、到这里我们找到了成员变了存储的位置,也额外找到一些类的其它结构存储位置。然后我们看到了一个baseMethodList
,顺带看看这个?经过lldb
打印结果如下:
从以上看出还是只是对象方法,并没有我们的类方法,然后我们继续去探索类方法的存储位置。
类方法
1、目前我们已经找到了类的属性、成员变量、对象方法的存储位置,这一节我们探索类方法的存储位置,我们在类中找过了所有与方法有关系的函数,都没有找到类方法的存储位置,那么我们是否有这么一个猜测,它是否在元类中?因为到目前为止,没有想到元类有什么作用。所以带着好奇心我们去看下元类中的bits
。
2、首先我们通过lldb
去看下bits
中的methods()
包含啥?但是我们怎么访问到元类呢?很简单之前对象的本质这篇文章中有介绍isa_t
这个联合体的时候介绍了一个掩码,那么我们通过这个掩码就可以得到元类,看下面结果:
3、从上图我们可以看到,类方法确实存储在了元类中。这个过程中我们不是拿的KGPerson.class
的地址,而是通过isa
取模然后地址偏移最后得到的元类,其它的都是和读取类的操作是一样的。
4、那么到此我们经过两篇文章的探索,大概分析了类的属性、成员变量、对象方法(实例方法)、类方法的存储位置。
总结
经过两篇文章的分析,我们探究了类的属性、成员变量、类方法、对象方法的存储位置,大概了解了一些类的内存结构。