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

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_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存储了当前类在编译期就已经确定的属性,方法,以及遵循的协议,而class_rw_t是运行时才确定,它会将class_ro_t的内容拷贝过去,然后再将当前类的分类方法这些属性,方法等拷贝其中

上一篇下一篇

猜你喜欢

热点阅读