承接上一篇OC类的探究分析一:类与元类
🍎 直接打印LGPerson.class,发现除了isa指针,还有其他内容。
尝试打印地址发现,
po 0x00000001000083a8 的打印结果是LGPerson
po 0x0000000100357140 的打印结果是NSObject
剩余的均无法直接打印出来
下图是定义的LGPerson类,包含一个成员变量“subject”,两个属性变量“name“和”hobby“,以及实例方法sayNB()和类方法say666(),那么这些内容是如何存储的呢?
打开源码查找objc_class,发现除了isa,还有superclass,cache,以及bits。cache暂时放一边(后续补充),先看一下bits。
呢么问题来了,想要查看bits里面的内容,要如何确定它的地址呢?
点进去cache_t查看发现,cache_t是一个结构体类型,里面包含 explicit_atomic<uintptr_t> _bucketsAndMaybeMask 和 union,其他是函数和全局变量,那么cache_t的大小就是这两个成员的大小之和,为16。
03
那么,bits的地址为LGPerson的首地址(0x100008380)平移32,即 0x100008380 + 0x20 = 0x1000083a0。
用 (class_data_bits_t *)0x00000001000083a0获取bits空间的指针地址,获取到指针地址,如何才能取到bits里面的数据呢?
看到这句代码注释,可以猜想到bits数据查找应当与读写相关
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
顺着这个想法寻找class_rw_t 相关方法
class_rw_t *data() const { return bits.data(); }
那么基本可以确定调用 data() 是可以得到相关数据
打印结果发现,得到的$3仍然是地址,那继续查找发现class_rw_t是结构体,那么得到的$3的地址就是指向这个结构体的。
继续阅读class_rw_t里面的内容,发现有这三个方法:
初步推断,这三个方法应该可以找到LGPerson的属性,方法,成员变量
先尝试一下properties()方法,看能不能达到想要的属性
通过打印输出结果,可以看到我们想要的内容存在以list里面,尝试打印$4.list
然而还要在进一步打印$5.ptr来拿到指针地址
先打印指针指向什么内容
打印结果显示properties()返回的是一个count=2的数组
*$6还是无法直接获取到属性,接下来再回头查看一下properties()这个方法,发现变量“v”是我们想要的东西,并且可能是通过get()方法获取。
尝试打印$7.get()
打印的内容是“name”和“hobby”这两个属性变量,由此可见成员变量”subject“和两个方法可能需要在methods()里面找。
先阅读以下methods()方法,和properties()差不多,那么可以顺这之前的思路尝试一下
method返回count=6的数组,但是打印结果为空
那么重新再分析property_array_t和method_array_t区别
进入property_array_t ——>property_t,发现property_t是一个结构体并且只有两个成员变量,如下代码
struct property_t { const char *name; const char *attributes;};
进入method_array_t——>method_t,method_t也是一个结构体,大致翻看一下,这里有一个 struct big{}
大致可以猜测,
第一个成员name应该是函数名
第二个成员type应该是函数类型
第三个成员imp应该是当前函数的指针地址
(但是里面内容挺长的,省略号为代码余下内容,篇幅太长,截断暂时不需要的内容)
struct method_t {
static const uint32_t smallMethodListFlag = 0x80000000;
method_t(const method_t &other) = delete; .
struct big {
SEL name;
const char *types;
MethodListIMP imp;
};
……
}
那么接下来尝试打印$7.get().big
打印结果显示,有sayNB(),hobby的get()、set()方法,name的get()、set()方法,以及init(),然而没有类方法say666()和成员变量subject,
那么实例方法和类方法的存储方式 不一样
(不用考虑在protocol()里寻找,因为这里面应该是与协议相关,而我们并没有去定义相关协议内容)
由此可见,只能再换个思路去寻找成员变量subject和类方法OC类的探究二:成员变量和类方法