美文网首页iOS面试总结
Runtime之runtime解析

Runtime之runtime解析

作者: Jimmy_L_Wang | 来源:发表于2019-06-19 23:33 被阅读0次

    OC中类的源码

    #if !OBJC_TYPES_DEFINED
    /// An opaque type that represents an Objective-C class.
    typedef struct objc_class *Class;
    
    /// Represents an instance of a class.
    struct objc_object {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    };
    
    /// A pointer to an instance of a class.
    typedef struct objc_object *id;
    #endif
    
    /// An opaque type that represents a method selector.
    typedef struct objc_selector *SEL;
    
    /// A pointer to the function of a method implementation. 
    #if !OBJC_OLD_DISPATCH_PROTOTYPES
    typedef void (*IMP)(void /* id, SEL, ... */ ); 
    #else
    typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); 
    #endif
    

    objc_object 源码

    struct objc_object {
    private:
        isa_t isa;
    
    public:
      ......
    }
    

    isa_t 源码

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

    objc_class 源码

    objc_class继承自objc_object

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

    isa指针

    isa指针.png

    isa指针是什么含义?

    指针型isa和非指针型isa,非指针型只有前30-40多位用来代表Class的地址,在寻址过程中只寻找30-40位的地址,就保证了我们可以寻找到想要的Class的地址,多出来的可以用来存储其他的相关内容,这样做可以达到一个节省内存的目的。

    isa指向

    isa指向.png
    • 实例在OC中对应的就是id类型,表述在runtime中对应的就是objc_objectobjc_object当中一个isa指针,对于实例来说他的isa指针指向他对应的Class(类对象)
    • Class在runtime中对应的是objc_class,objc_class又继承自objc_object,所以说Class也是一种对象,称之为类对象,由于继承自objc_object所以也有一个isa指针,这个指针指向的是元类对象。
    • 在进行方法调用的时候,在调用实例的实例方法时,实际上是通过isa指针到类对象当中去进行方法查找,如果调用的是一个类方法,通过类对象的isa指针到元类对象中进行方法的查找。

    cache_t

    • 用于快速查找方法执行函数

    • 是可增量扩展哈希表结构

      当结构所存储的量在增大的过程中,他会增量的扩大他的内存空间,来支持更多的缓存。用哈希表来实现数据结构,主要是为了提高查找效率

    • 局部性原理的最佳应用

      局部性原理是指计算机在执行某个程序时,倾向于使用最近使用的数据。局部性原理有两种表现形式:时间局部性和空间局部性。

      时间局部性是指被引用过的存储器位置很可能会被再次引用,例如:重复的引用一个变量时则表现出较好的时间局部性

      空间局部性是指被引用过的存储器位置附近的数据很可能将被引用;例如:遍历二维数组时按行序访问数据元素具有较好的空间局部性

    cache_t源码

    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__
        MethodCacheIMP _imp; //无类型的函数指针
        cache_key_t _key;  //方法选择器
    #else
        cache_key_t _key;
        MethodCacheIMP _imp;
    #endif
    
    public:
        inline cache_key_t key() const { return _key; }
        inline IMP imp() const { return (IMP)_imp; }
        inline void setKey(cache_key_t newKey) { _key = newKey; }
        inline void setImp(IMP newImp) { _imp = newImp; }
    
        void set(cache_key_t newKey, IMP newImp);
    };
    
    
    struct cache_t {
        struct bucket_t *_buckets;
        mask_t _mask;
        mask_t _occupied;
    
    public:
        struct bucket_t *buckets();
        mask_t mask();
        mask_t occupied();
        void incrementOccupied();
        void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
        void initializeToEmpty();
    
        mask_t capacity();
        bool isConstantEmptyCache();
        bool canBeFreed();
    
        static size_t bytesForCapacity(uint32_t cap);
        static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
    
        void expand();
        void reallocate(mask_t oldCapacity, mask_t newCapacity);
        struct bucket_t * find(cache_key_t key, id receiver);
    
        static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
    };
    
    cache_t结构.png

    class_data_bits_t

    • class_data_bits_t主要是对class_rw_t的封装

    • class_rw_t代表了类相关的读写信息、对class_ro_t的封装

      class_rw_t给类添加的一些分类当中的方法,属性,或者协议,都是在这个数据结构当中

    • class_ro_t代表了类相关的只读信息。

    源码

    class_data_bits_t

    struct class_data_bits_t {
    
        // Values are the FAST_ flags above.
        uintptr_t bits;
    private:
        bool getBit(uintptr_t bit)
        {
            return bits & bit;
        }
    .........
      
    public:
    
        class_rw_t* data() {
            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;
        }
      .......
    }
    
    

    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
    
        void setFlags(uint32_t set) 
        {
            OSAtomicOr32Barrier(set, &flags);
        }
    
        void clearFlags(uint32_t clear) 
        {
            OSAtomicXor32Barrier(clear, &flags);
        }
    
        // 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_t.png

    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;
    
        method_list_t *baseMethods() const {
            return baseMethodList;
        }
    };
    

    图形结构展示

    class_ro_t.png

    ro意为readOnly,即类本身拥有的东西,已经完成后续不会再增加删除,所以使用了一维数组存储。

    method_t源码实现

    struct method_t {
        SEL name;
        const char *types;
        MethodListIMP imp;
    
        struct SortBySELAddress :
            public std::binary_function<const method_t&,
                                        const method_t&, bool>
        {
            bool operator() (const method_t& lhs,
                             const method_t& rhs)
            { return lhs.name < rhs.name; }
        };
    };
    

    函数与method_t的关系

    method_t.png

    Type Encodings

    • const char* types
    type_encoding.png

    总结

    objc整体结构.png

    相关文章

      网友评论

        本文标题:Runtime之runtime解析

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