美文网首页
iOS底层原理总结 - Class的本质↑

iOS底层原理总结 - Class的本质↑

作者: Doubleyz | 来源:发表于2019-12-21 17:36 被阅读0次

    通过对面试题的分析探索问题的本质内容

    iOS底层原理总结 - OC对象的分类↑
    iOS底层原理总结 - OC对象的本质↑

    Class的本质

    我们知道不管是类对象还是元类对象,类型都是Class,class和mete-class的底层都是objc_class结构体的指针,内存中就是结构体,本章来探寻Class的本质

    Class objectClass = [NSObject class];        
    Class objectMetaClass = object_getClass([NSObject class]);
    

    点击Class来到内部,我们可以发现

    typedef struct objc_class *Class;
    

    Class对象其实是一个指向objc_class结构体的指针。因此我们可以说类对象或元类对象在内存中其实就是objc_class结构体。

    我们来到objc_class内部,可以看到这段在底层原理中经常出现的代码。

    struct objc_class {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    
    #if !__OBJC2__
        Class _Nullable super_class                              OBJC2_UNAVAILABLE;
        const char * _Nonnull name                               OBJC2_UNAVAILABLE;
        long version                                             OBJC2_UNAVAILABLE;
        long info                                                OBJC2_UNAVAILABLE;
        long instance_size                                       OBJC2_UNAVAILABLE;
        struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
        struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
        struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
        struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
    #endif
    
    } OBJC2_UNAVAILABLE;
    /* Use `Class` instead of `struct objc_class *` */
    

    这部分代码相信在文章中很常见,但是OBJC2_UNAVAILABLE 说明这些代码已经不在使用了。那么目前objc_class的结构是什么样的呢?我们通过objc源代码中去查找objc_class结构体的内容。

    部分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() { 
            return bits.data();
        }
        void setData(class_rw_t *newData) {
            bits.setData(newData);
        }
        //后面代码省略
        ....
    };
    

    我们发现这个结构体继承 objc_object 并且结构体内有一些函数,因为这是c++结构体,在c上做了扩展,因此结构体中可以包含函数。我们来到objc_object内,截取部分代码

    objc_object内部分代码

    我们发现objc_object中有一个isa指针,那么objc_class继承objc_object,也就同样拥有一个isa指针

    那么我们之前了解到的,类中存储的类的成员变量信息,实例方法,属性名等这些信息在哪里呢。我们来到class_rw_t中,截取部分代码,我们发现class_rw_t中存储着方法列表,属性列表,协议列表等内容。

    struct class_rw_t {
        // Be warned that Symbolication knows the layout of this structure.
        uint32_t flags; // 标记
        uint32_t version; // 版本信息
    
        const class_ro_t *ro;
    
        method_array_t methods; // 方法列表
        property_array_t properties; // 属性列表
        protocol_array_t protocols; // 协议列表
    
        Class firstSubclass;
        Class nextSiblingClass;
    
        char *demangledName;
    
    #if SUPPORT_INDEXED_ISA
        uint32_t index;
    #endif
        // 后面代码省略
        ...
    }
    

    而class_rw_t是通过bits调用data方法得来的,我们来到data方法内部实现。我们可以看到,data函数内部仅仅对bits进行&FAST_DATA_MASK操作

        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() { 
            return bits.data();
        }
        // 后面源码省略
        ...
    }
    

    点击 return bits.data()来到

    public:
    
        class_rw_t* data() {
            return (class_rw_t *)(bits & FAST_DATA_MASK);
        }
    

    而成员变量信息则是存储在class_ro_t内部中的,我们来到class_ro_t源码

    struct class_ro_t {
        uint32_t flags;
        uint32_t instanceStart;
        uint32_t instanceSize; // 实例大小
    #ifdef __LP64__
        uint32_t reserved;
    #endif
    
        const uint8_t * ivarLayout;
        
        const char * name;// 类名
        method_list_t * baseMethodList;
        protocol_list_t * baseProtocols;
        const ivar_list_t * ivars; // 成员变量列表
    
        const uint8_t * weakIvarLayout;
        property_list_t *baseProperties;
    
        // This field exists only when RO_HAS_SWIFT_INITIALIZER is set.
        _objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];
    
        _objc_swiftMetadataInitializer swiftMetadataInitializer() const {
            if (flags & RO_HAS_SWIFT_INITIALIZER) {
                return _swiftMetadataInitializer_NEVER_USE[0];
            } else {
                return nil;
            }
        }
    
        method_list_t *baseMethods() const {
            return baseMethodList;
        }
    
        class_ro_t *duplicate() const {
            if (flags & RO_HAS_SWIFT_INITIALIZER) {
                size_t size = sizeof(*this) + sizeof(_swiftMetadataInitializer_NEVER_USE[0]);
                class_ro_t *ro = (class_ro_t *)memdup(this, size);
                ro->_swiftMetadataInitializer_NEVER_USE[0] = this->_swiftMetadataInitializer_NEVER_USE[0];
                return ro;
            } else {
                size_t size = sizeof(*this);
                class_ro_t *ro = (class_ro_t *)memdup(this, size);
                return ro;
            }
        }
    };
    
    窥探struct objc_class的结构

    从64位cup架构(即iPhone5s)开始,isa需要进行一次位运算,才能计算出真实的地址


    ISA_MASk
    isa指针 class对象的superclass指针 meta-class对象的superclass指针

    最后我们用一张图来总结

    isa、superclass总结

    iOS底层原理总结 - 文集

    文中如有总结不对、不到位的地方欢迎指出。谢谢~

    相关文章

      网友评论

          本文标题:iOS底层原理总结 - Class的本质↑

          本文链接:https://www.haomeiwen.com/subject/cyygnctx.html