美文网首页IOS开发知识点
iOS 类的结构分析

iOS 类的结构分析

作者: ugpass | 来源:发表于2020-09-15 12:00 被阅读0次

    1. 类的初探

    isa结构解析中,自定义LSPerson 类继承自NSObject,重写成C++代码如下

    struct LSPerson_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
    };
    

    struct NSObject_IMPL结构体定义如下

    struct NSObject_IMPL {
        Class isa;
    };
    

    typedef struct objc_class *Class;
    Class为指向 结构体struct objc_class的指针,所以继承自NSObject的对象中都有isa成员变量。那么NSObject的isa来自何处呢?

    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() const {
            return bits.data();
        }
    
        ...省略的函数
    }
    

    由此可以知道struct objc_class继承自struct objc_object

    struct objc_object源码如下

    struct objc_object {
    private:
        isa_t isa;
    
    public:
        ...省略的函数
    }
    

    总结:在OC层,对象的isa指向对象的类,对象的类继承自NSObjectNSObject是以结构体struct objc_class为模版创建的;在C++层,struct objc_class继承自struct objc_objectstruct objc_object内部有isa成员变量。

    2. 类的结构分析

    由结构体struct objc_class源码可知,类的信息存储在class_data_bits_t bits;中。
    为了取到class_data_bits_t bits;,需要在结构体struct objc_class进行地址偏移计算。

    1. Class ISA; //结构体指针类型 8字节
    2. Class superclass;//结构体指针类型 8字节
    3. cache_t cache;

    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;
    
        ...其他全局变量
    
    #if __LP64__
        uint16_t _flags;
    #endif
        uint16_t _occupied;
    
        ...其他方法
    

    cache_t结构体计算:explicit_atomic<uintptr_t> _maskAndBuckets; long类型 8字节; mask_t _mask_unused; int类型 4字节; uint16_t _flags; short类型 2字节;uint16_t _occupied; short类型 2字节。根据内存对齐原则cache_t大小为16字节。故为了取到class_data_bits_t bits;,需要在结构体struct objc_class对首地址进行偏移32字节

    探索流程:

    //获取LSPerson类首地址
    (lldb) p/x LSPerson.class
    (Class) $0 = 0x00000001000021c8 LSPerson
    
    //获取类isa中对内存信息
    (lldb) x/4gx 0x00000001000021c8
    (lldb) x/4gx 0x00000001000021c8
    0x1000021c8: 0x00000001000021a0 0x00007fff944ae118
    0x1000021d8: 0x00007fff6cd18140 0x0000801000000000
    
    //根据地址偏移0x1000021c8 -> 0x1000021d8 获取bits信息
    (lldb) p (class_data_bits_t *)0x1000021d8
    (class_data_bits_t *) $1 = 0x00000001000021e8
    
    //根据struct objc_class中data()函数获取class_rw_t
    (lldb) p $1->data()
    (class_rw_t *) $2 = 0x00000001010224b0
    
    (lldb) p *($2)
    (class_rw_t) $4 = {
      flags = 2148007936
      witness = 0
      ro_or_rw_ext = {
        std::__1::atomic<unsigned long> = 4294975744
      }
      firstSubclass = nil
      nextSiblingClass = NSUUID
    }
    
    (lldb) p $4.methods()      //打印出对象方法列表
    (lldb) p $4.properties()    //打印出属性列表
    (lldb) p $4.protocols()     //打印出协议列表
    

    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;
    
    private: 
        ...省去其他函数
    
    public: 
        ...省去其他函数
        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 *>();
        } 
    
        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()即可获取类的方法列表,属性列表以及协议列表。

    相关文章

      网友评论

        本文标题:iOS 类的结构分析

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