10期_iOS_类的本质(2)
2023-08-14 本文已影响0人
萧修
同类型的对象可以创建多个,但是类只有一个
而类在编译期创建,并只有一份。
查看类的初始化,下面为clang之后的代码。
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
CJPerson * person = ((CJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((CJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("CJPerson"), sel_registerName("alloc")), sel_registerName("init"));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_fg_3995175d2_v6g81lknk8jdwh0000gn_T_main_e6fa2f_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("class")));
}
return 0;
}
获取类的通过objc_getClass
源码文件中
__OBJC_RW_DLLIMPORT struct objc_class *objc_getClass(const char *);
typedef struct objc_class *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 ISA注释了,继承自objc_object,ISA来自父类
类的真正类型是objc_class,继承自objc_object(NSObject的底层结构),万物皆对象,类也是一个对象。
类的数据结构
ISA、supperclass、cache、bits
- ISA
- supperclass
- cache_t cache
方法缓存:方法涉及到,方法查找流程,缓存策略,动态扩容等
struct cache_t {
struct bucket_t *buckets() const;
mask_t mask() const;
}
struct bucket_t {
private:
// IMP-first is better for arm64e ptrauth and no worse for arm64.
// SEL-first is better for armv7* and i386 and x86_64.
#if __arm64__
explicit_atomic<uintptr_t> _imp;
explicit_atomic<SEL> _sel;
#else
explicit_atomic<SEL> _sel;
explicit_atomic<uintptr_t> _imp;
#endif
}
buckets:装方法的桶子,里面存放方法的实现imp,根据方法编号sel生成key
bucket_t:结构体指针,占用8个字节,
- class_data_bits_t bits
数据存放的地方,bits里面有data,data是从macgo读取的class_rw_t
而class_rw_t
中结构体中有方法列表,属性列表,协议列表。里面的class_ro_t
struct class_data_bits_t {
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
}
struct class_rw_t {
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);
}
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};
}
}
}
struct class_ro_t {
WrappedPtr<method_list_t, method_list_t::Ptrauth> baseMethods;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
property_list_t *baseProperties;
}
class_ro_t中有,方法列表,协议列表,实例变量列表,属性列表
类添加的属性方法
向类中实例变量,属性,方法,类方法
- 成员变量存放在
class_ro_t
中的ivar_list
- 属性在
class_rw_t
中的property_list
和class_ro_t
中的property_list_t
都存着一份,并且会生成实例变量,和对应的方法 - 方法在
class_rw_t
中的method_array_t
和class_ro_t
中的的method_list_t
都存着一份 - 对象方法存放在类里面
- 类方法存放在元类里面
class_ro_t
存储了当前类在编译期就已经确定的属性,方法,以及遵循的协议,而class_rw_t
是运行时才确定,它会将class_ro_t
的内容拷贝过去,然后再将当前类的分类方法这些属性,方法等拷贝其中