OC类的探究分析二:类的内存结构之属性和实例方法

承接上一篇OC类的探究分析一:类与元类

  直接打印LGPerson.class,发现除了isa指针,还有其他内容。


01


尝试打印地址发现,

        po 0x00000001000083a8 的打印结果是LGPerson

        po 0x0000000100357140 的打印结果是NSObject

剩余的均无法直接打印出来       



下图是定义的LGPerson类,包含一个成员变量“subject”,两个属性变量“name“和”hobby“,以及实例方法sayNB()和类方法say666(),那么这些内容是如何存储的呢?

04

打开源码查找objc_class,发现除了isa,还有superclass,cache,以及bits。cache暂时放一边(后续补充),先看一下bits。


呢么问题来了,想要查看bits里面的内容,要如何确定它的地址呢?

    点进去cache_t查看发现,cache_t是一个结构体类型,里面包含 explicit_atomic _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类的探究二:成员变量和类方法







你可能感兴趣的:(OC类的探究分析二:类的内存结构之属性和实例方法)