4.iOS底层学习之类的结构
类的结构
前面我们通过探索了解到一个类实际是一个结构体objc_class,objc_class的实现如下:
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// 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 superclass;
-cache_t cache;
-class_data_bits_t bits;
还有一个在objc_object中的isa,我们分别来看下这些成员变量分别存储的是什么东西!
类的isa
1)、对象的isa指向类;
2)、类的isa指向元类;
3)、元类的isa指向根元类;
4)、根元类的isa指向自己;
元类是系统编译器自动创建的
类的superClass
1)、类的superClass指向父类;
2)、父类的superClass指向基类(NSObject);
3)、元类的superClass指向元类的父类;
4)、元类的父类的superClass指向根元类;
5)、根元类的superClass指向基类NSObject;
苹果官方经典链路图:
![](https://img.haomeiwen.com/i1678439/61ae1fae704d3b9b.png)
类的cache
我们点进去看下cache_t的定义和结构:
struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
union {
struct {
explicit_atomic<mask_t> _maybeMask;
#if __LP64__
uint16_t _flags;
#endif
uint16_t _occupied;
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache;
};
//此处省略下方一些方法代码
};
可以看到,cache的结构大致如下:
_bucketsAndMaybeMask;是一个unsigned long 类型实际,占8字节;
一个联合体,联合体的大小是最大成员的大小,_maybeMask是uint32_t类型占4字节,_flags占2字节,_occupied占2字节,_originalPreoptCache是指针类型 占8字节,所以联合体大小是8字节;所以cache_t占16字节;
类的bits
我们可以通过以上分析完毕的内存结构占位来通过lldb调试,指针平移拿到bits来具体看看里面装的到底是什么。过程如下:
![](https://img.haomeiwen.com/i1678439/0dba6d80e3ec87d2.jpg)
步骤:
1、通过x/4gx LGPerson.class 拿到LGPerson类的首地址。
2、然后进行指针平移32个字节拿到bits。
3、查看bits的结构发现里面比较重要的是data,他是class_rw_t类型的,然后通过指针获取data的相关数据,返回了一个class_rw_t的数据,对应的$43;
4、然后查看class_rw_t的结构,可以看到里面重要的信息properties,所以接着获取,打印得到一堆东西,类型是list_array_tt,可以看到里面的有list数据,接着尝试获取list;
5、接着尝试获取list下的ptr,打印看到是property_list_t,命名看起来像属性列表,查看下这个结构如下:
struct property_list_t : entsize_list_tt<property_t, property_list_t, 0> {
};
那么可以了解property_list_t继承自entsize_list_tt,然后搜索查找entsize_list_tt可以看到里面有get方法,传入的int类型:
struct entsize_list_tt {
uint32_t entsizeAndFlags;
uint32_t count;
Element& getOrEnd(uint32_t i) const {
ASSERT(i <= count);
return *PointerModifier::modify(*this, (Element *)((uint8_t *)this + sizeof(*this) + i*entsize()));
}
Element& get(uint32_t i) const {
ASSERT(i < count);
return getOrEnd(i);
}
size_t byteSize() const {
return byteSize(entsize(), count);
}
//此处省略下方若干代码
}
所以我们尝试调用该方法,然后打印出我们在LGPerson声明的两个属性,类型为 property_t:
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *hobby;
类的属性
所以,类的属性存放在了NSObject.class -> class_data_bits_t -> class_rw_t -> property_array_t -> property_list_t 中
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:
using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t, class_rw_ext_t, PTRAUTH_STR("class_ro_t"), PTRAUTH_STR("class_rw_ext_t")>;
const ro_or_rw_ext_t get_ro_or_rwe() const {
return ro_or_rw_ext_t{ro_or_rw_ext};
}
void set_ro_or_rwe(const class_ro_t *ro) {
ro_or_rw_ext_t{ro, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_relaxed);
}
void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {
// the release barrier is so that the class_rw_ext_t::ro initialization
// is visible to lockless readers
rwe->ro = ro;
ro_or_rw_ext_t{rwe, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_release);
}
class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);
public:
void setFlags(uint32_t set)
{
__c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);
}
void clearFlags(uint32_t clear)
{
__c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);
}
// set and clear must not overlap
void changeFlags(uint32_t set, uint32_t clear)
{
ASSERT((set & clear) == 0);
uint32_t oldf, newf;
do {
oldf = flags;
newf = (oldf | set) & ~clear;
} while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
}
class_rw_ext_t *ext() const {
return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
}
class_rw_ext_t *extAllocIfNeeded() {
auto v = get_ro_or_rwe();
if (fastpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
} else {
return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
}
}
class_rw_ext_t *deepCopy(const class_ro_t *ro) {
return extAlloc(ro, true);
}
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_or_rw_ext)->ro;
}
return v.get<const class_ro_t *>(&ro_or_rw_ext);
}
void set_ro(const class_ro_t *ro) {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro;
} else {
set_ro_or_rwe(ro);
}
}
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 *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->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 *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->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 *>(&ro_or_rw_ext)->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
}
}
};
根据这个结构体我们可以看到通过 class_rw_t能拿到:
-protocol_array_t protocols() //协议
-property_array_t properties() //属性
-class_ro_t *ro
这几个比较重要的信息,不了解ro是做什么的于是点进去看下结构。
class_ro_t
看下源码的结构,里面可谓是大千世界。我删除一部分标志位,来看些相对看着比较重要的信息:
struct class_ro_t {
void *baseMethodList; //方法列表
protocol_list_t * baseProtocols; //协议列表
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
//此处省略一些方法实现
}
};
可以看到这个结构体中有一些信息貌似和class_rw_t重合了,我去了解了一部分相关知识,这个貌似和编译和运行时的设计有关系,具体的后面会写笔记深入的了解下。
类的成员变量
根据上面的探索,可以得到:
成员变量存放在了NSObject.class -> class_data_bits_t -> class_rw_t -> class_ro_t -> ivars中;
类的实例方法
类的实例方法存放在了NSObject.class -> class_data_bits_t -> class_rw_t -> methods中
类方法
类的实例方法存放在了NSObject.class -> metaClass -> class_data_bits_t -> class_rw_t -> method_array_t -> method_list_t -> method_t -> big中