iOS 类的结构分析
1. 类的初探
在isa结构解析中,自定义LSPerson
类继承自NSObject
,重写成C++代码如下
struct LSPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
};
struct NSObject_IMPL
结构体定义如下
struct NSObject_IMPL {
Class isa;
};
typedef struct objc_class *Class;
Class为指向 结构体struct objc_class
的指针,所以继承自NSObject
的对象中都有isa成员变量。那么NSObject
的isa来自何处呢?
objc_class
源码如下
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() const {
return bits.data();
}
...省略的函数
}
由此可以知道struct objc_class
继承自struct objc_object
struct objc_object
源码如下
struct objc_object {
private:
isa_t isa;
public:
...省略的函数
}
总结:在OC层,对象的isa指向对象的类,对象的类继承自NSObject
,NSObject
是以结构体struct objc_class
为模版创建的;在C++层,struct objc_class
继承自struct objc_object
,struct objc_object
内部有isa成员变量。
2. 类的结构分析
由结构体struct objc_class
源码可知,类的信息存储在class_data_bits_t bits;
中。
为了取到class_data_bits_t bits;
,需要在结构体struct objc_class
进行地址偏移计算。
- Class ISA; //结构体指针类型 8字节
- Class superclass;//结构体指针类型 8字节
- cache_t cache;
cache_t源码
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
explicit_atomic<struct bucket_t *> _buckets;
explicit_atomic<mask_t> _mask;
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
explicit_atomic<uintptr_t> _maskAndBuckets;
mask_t _mask_unused;
...其他全局变量
#if __LP64__
uint16_t _flags;
#endif
uint16_t _occupied;
...其他方法
cache_t
结构体计算:explicit_atomic<uintptr_t> _maskAndBuckets;
long类型 8字节; mask_t _mask_unused;
int类型 4字节; uint16_t _flags;
short类型 2字节;uint16_t _occupied;
short类型 2字节。根据内存对齐原则cache_t
大小为16字节。故为了取到class_data_bits_t bits;
,需要在结构体struct objc_class
对首地址进行偏移32字节。
探索流程:
//获取LSPerson类首地址
(lldb) p/x LSPerson.class
(Class) $0 = 0x00000001000021c8 LSPerson
//获取类isa中对内存信息
(lldb) x/4gx 0x00000001000021c8
(lldb) x/4gx 0x00000001000021c8
0x1000021c8: 0x00000001000021a0 0x00007fff944ae118
0x1000021d8: 0x00007fff6cd18140 0x0000801000000000
//根据地址偏移0x1000021c8 -> 0x1000021d8 获取bits信息
(lldb) p (class_data_bits_t *)0x1000021d8
(class_data_bits_t *) $1 = 0x00000001000021e8
//根据struct objc_class中data()函数获取class_rw_t
(lldb) p $1->data()
(class_rw_t *) $2 = 0x00000001010224b0
(lldb) p *($2)
(class_rw_t) $4 = {
flags = 2148007936
witness = 0
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = 4294975744
}
firstSubclass = nil
nextSiblingClass = NSUUID
}
(lldb) p $4.methods() //打印出对象方法列表
(lldb) p $4.properties() //打印出属性列表
(lldb) p $4.protocols() //打印出协议列表
class_rw_t源码
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint16_t witness;
#if SUPPORT_INDEXED_ISA
uint16_t index;
#endif
explicit_atomic<uintptr_t> ro_or_rw_ext;
Class firstSubclass;
Class nextSiblingClass;
private:
...省去其他函数
public:
...省去其他函数
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>()->ro;
}
return v.get<const class_ro_t *>();
}
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->methods;
} else {
return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
}
}
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->properties;
} else {
return property_array_t{v.get<const class_ro_t *>()->baseProperties};
}
}
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
}
}
};
根据已获取的class_rw_t,调用结构体内部函数methods()
、properties()
、protocols()
即可获取类的方法列表,属性列表以及协议列表。