美文网首页
iOS runtime源码分析 - Class

iOS runtime源码分析 - Class

作者: 某年某月某日晴 | 来源:发表于2020-09-23 21:05 被阅读0次

    Runtime源码下载

    Runtime的API文档:描述了Objective-C runtime动态库提供的一些函数和数据结构。

    iOS上关于Runtime的源码其实就是objc4,我们在objc4源码上能看到最新版本为objc-781

    源码地址打开后是这个样子的
    下载解压后打开objc.xcodeproj我们就可以愉快的浏览源码了
    解压后这个样子

    Class的本质

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

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

    搜索objc_class结构体的定义,我们可以发现有两个文件中都包含了objc_class的定义,一个是objc-runtime-new.h,一个是objc-runtime-old.h
    我们忽略old直接看new,因为old是objc2之前的用法,现在已经弃用.

    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();
        }
        void setData(class_rw_t *newData) {
            bits.setData(newData);
        }
    
        void setInfo(uint32_t set) {
            ASSERT(isFuture()  ||  isRealized());
            data()->setFlags(set);
        }
    
        void clearInfo(uint32_t clear) {
            ASSERT(isFuture()  ||  isRealized());
            data()->clearFlags(clear);
        }
    

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

    struct objc_object {
    private:
        isa_t isa;
    
    public:
    
        // ISA() assumes this is NOT a tagged pointer object
        Class ISA();
    
        // rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
        Class rawISA();
    
        // getIsa() allows this to be a tagged pointer object
        Class getIsa();
    

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

    isa_t isa

    union isa_t {
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
    
        Class cls;
        uintptr_t bits;
    #if defined(ISA_BITFIELD)
        struct {
            ISA_BITFIELD;  // defined in isa.h
        };
    #endif
    };
    

    isa_t是个联合体,我们只关心它的Class cls的联合部分。而Class又是个objc_class *。每个对象里面有个isa的成员变量,指向它代表一个类的东西。从OC的角度看,每个对象都能从isa中寻找到它的类的相关信息。

    objc_object与 objc_class关系

    Runtime中定义了一个叫做 objc_object 的结构体,代表OC层的对象
    定义了一个objc_class的结构体,代表OC层的类,可以清楚看到, objc_class是继承objc_object的,因此,类也是一个objc_object的对象

    Class superclass

    直接附一张实例,类,元类之间isa和superclass的关系图


    虚线 isa指针,实线superclass

    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;
    ......
    #else
    #error Unknown cache mask storage type.
    #endif
        
    #if __LP64__
        uint16_t _flags;
    #endif
        uint16_t _occupied;
    ......
    };
    

    class_data_bits_t

    是存储类的方法、属性、协议等信息的地方

    struct class_data_bits_t {
        friend objc_class;
    
        // Values are the FAST_ flags above.
        uintptr_t bits;
    ......
        class_rw_t* data() const {
            return (class_rw_t *)(bits & FAST_DATA_MASK);
        }
        void setData(class_rw_t *newData)
        {
            ASSERT(!data()  ||  (newData->flags & (RW_REALIZING | RW_FUTURE)));
            // Set during realization or construction only. No locking needed.
            // Use a store-release fence because there may be concurrent
            // readers of data and data's contents.
            uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
            atomic_thread_fence(memory_order_release);
            bits = newBits;
        }
    
        // Get the class's ro data, even in the presence of concurrent realization.
        // fixme this isn't really safe without a compiler barrier at least
        // and probably a memory barrier when realizeClass changes the data field
        const class_ro_t *safe_ro() {
            class_rw_t *maybe_rw = data();
            if (maybe_rw->flags & RW_REALIZED) {
                // maybe_rw is rw
                return maybe_rw->ro();
            } else {
                // maybe_rw is actually ro
                return (class_ro_t *)maybe_rw;
            }
        }
    ......
    

    class_data_bits_t中只有一个bits变量,从注释中得知里面存着以FAST_开头的定义的flags,例如FAST_HAS_DEFAULT_RR、FAST_CACHE_HAS_CXX_DTOR等等。
    class_data_bits_t结构体里并没有看到方法、属性相关的内容,那么我们之前了解到的,类中存储的类的成员变量信息,实例方法,属性名等这些信息在哪里呢。通过data()方法可以看到bits变量中还存有一个class_rw_t类型的data指针。

    我们来到class_rw_t中,截取部分代码,我们发现class_rw_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;
    ......
        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 *>();
        }
    
        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 = 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 *>()->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()方法,获取的便是方法列表,属性列表,协议列表.
    那么成员变量存在哪里呢,这时候我们发现了一个ro方法,会返回一个class_ro_t的结构体,我们来到class_ro_t内查看,找到了成员变量ivars。

    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;
            }
        }
    }
    

    最后总结通过一张图进行总结

    image

    在class_ro_t结构体中其实有很多的成员变量和方法,其实class_rw_t中的ro,在类的编译期就已经确定了属性、方法以及要遵循的协议,objc_class中的bits中的data部分存放了ro信息。而在runtime运行之后,准确的说是在运行runtime的realizeClass方法时,会生成class_rw_t结构体,该结构体包含了class_ro_t,并且更新了data部分。换成了class_rw_t结构体的地址。

    遗留待研究问题:

    1,分类的底层结构
    2,实例方法和类方法区别,相应存储位置

    参考资料:
    iOS源码
    iOS底层原理总结 - 文集
    重学OC第四篇:类结构之bits

    相关文章

      网友评论

          本文标题:iOS runtime源码分析 - Class

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