美文网首页
4.iOS底层学习之类的结构

4.iOS底层学习之类的结构

作者: 牛牛大王奥利给 | 来源:发表于2021-06-21 17:30 被阅读0次

类的结构

前面我们通过探索了解到一个类实际是一个结构体objc_class,objc_class的实现如下:

struct objc_class : objc_object {
  objc_class(const objc_class&) = delete;
  objc_class(objc_class&&) = delete;
  void operator=(const objc_class&) = delete;
  void operator=(objc_class&&) = delete;
    // 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 superclass;
-cache_t cache;
-class_data_bits_t bits;
还有一个在objc_object中的isa,我们分别来看下这些成员变量分别存储的是什么东西!

类的isa

1)、对象的isa指向类;
2)、类的isa指向元类;
3)、元类的isa指向根元类;
4)、根元类的isa指向自己;
元类是系统编译器自动创建的

类的superClass

1)、类的superClass指向父类;
2)、父类的superClass指向基类(NSObject);
3)、元类的superClass指向元类的父类;
4)、元类的父类的superClass指向根元类;
5)、根元类的superClass指向基类NSObject;

苹果官方经典链路图:


isa流程图.png

类的cache

我们点进去看下cache_t的定义和结构:

struct cache_t {
private:
    explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
    union {
        struct {
            explicit_atomic<mask_t>    _maybeMask;
#if __LP64__
            uint16_t                   _flags;
#endif
            uint16_t                   _occupied;
        };
        explicit_atomic<preopt_cache_t *> _originalPreoptCache;
    };
//此处省略下方一些方法代码
};

可以看到,cache的结构大致如下:
_bucketsAndMaybeMask;是一个unsigned long 类型实际,占8字节;
一个联合体,联合体的大小是最大成员的大小,_maybeMask是uint32_t类型占4字节,_flags占2字节,_occupied占2字节,_originalPreoptCache是指针类型 占8字节,所以联合体大小是8字节;所以cache_t占16字节;

类的bits

我们可以通过以上分析完毕的内存结构占位来通过lldb调试,指针平移拿到bits来具体看看里面装的到底是什么。过程如下:


451624436083_.pic_hd.jpg

步骤:
1、通过x/4gx LGPerson.class 拿到LGPerson类的首地址。
2、然后进行指针平移32个字节拿到bits。
3、查看bits的结构发现里面比较重要的是data,他是class_rw_t类型的,然后通过指针获取data的相关数据,返回了一个class_rw_t的数据,对应的$43;
4、然后查看class_rw_t的结构,可以看到里面重要的信息properties,所以接着获取,打印得到一堆东西,类型是list_array_tt,可以看到里面的有list数据,接着尝试获取list;
5、接着尝试获取list下的ptr,打印看到是property_list_t,命名看起来像属性列表,查看下这个结构如下:

struct property_list_t : entsize_list_tt<property_t, property_list_t, 0> {
};

那么可以了解property_list_t继承自entsize_list_tt,然后搜索查找entsize_list_tt可以看到里面有get方法,传入的int类型:

struct entsize_list_tt {
    uint32_t entsizeAndFlags;
    uint32_t count;
    Element& getOrEnd(uint32_t i) const { 
        ASSERT(i <= count);
        return *PointerModifier::modify(*this, (Element *)((uint8_t *)this + sizeof(*this) + i*entsize()));
    }
    Element& get(uint32_t i) const { 
        ASSERT(i < count);
        return getOrEnd(i);
    }
    size_t byteSize() const {
        return byteSize(entsize(), count);
    }
//此处省略下方若干代码
}

所以我们尝试调用该方法,然后打印出我们在LGPerson声明的两个属性,类型为 property_t:

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *hobby;

类的属性

所以,类的属性存放在了NSObject.class -> class_data_bits_t -> class_rw_t -> property_array_t -> property_list_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;

private:
    using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t, class_rw_ext_t, PTRAUTH_STR("class_ro_t"), PTRAUTH_STR("class_rw_ext_t")>;

    const ro_or_rw_ext_t get_ro_or_rwe() const {
        return ro_or_rw_ext_t{ro_or_rw_ext};
    }

    void set_ro_or_rwe(const class_ro_t *ro) {
        ro_or_rw_ext_t{ro, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_relaxed);
    }

    void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {
        // the release barrier is so that the class_rw_ext_t::ro initialization
        // is visible to lockless readers
        rwe->ro = ro;
        ro_or_rw_ext_t{rwe, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_release);
    }

    class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);

public:
    void setFlags(uint32_t set)
    {
        __c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);
    }

    void clearFlags(uint32_t clear) 
    {
        __c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);
    }

    // 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_ext_t *ext() const {
        return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
    }

    class_rw_ext_t *extAllocIfNeeded() {
        auto v = get_ro_or_rwe();
        if (fastpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
        } else {
            return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
        }
    }

    class_rw_ext_t *deepCopy(const class_ro_t *ro) {
        return extAlloc(ro, true);
    }

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

    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_or_rw_ext)->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 *>(&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};
        }
    }
};

根据这个结构体我们可以看到通过 class_rw_t能拿到:
-protocol_array_t protocols() //协议
-property_array_t properties() //属性
-class_ro_t *ro
这几个比较重要的信息,不了解ro是做什么的于是点进去看下结构。

class_ro_t

看下源码的结构,里面可谓是大千世界。我删除一部分标志位,来看些相对看着比较重要的信息:

struct class_ro_t {
    void *baseMethodList; //方法列表
    protocol_list_t * baseProtocols; //协议列表
    const ivar_list_t * ivars;
    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
    method_list_t *baseMethods() const {
        //此处省略一些方法实现
      }
};

可以看到这个结构体中有一些信息貌似和class_rw_t重合了,我去了解了一部分相关知识,这个貌似和编译和运行时的设计有关系,具体的后面会写笔记深入的了解下。

类的成员变量

根据上面的探索,可以得到:
成员变量存放在了NSObject.class -> class_data_bits_t -> class_rw_t -> class_ro_t -> ivars中;

类的实例方法

类的实例方法存放在了NSObject.class -> class_data_bits_t -> class_rw_t -> methods中

类方法

类的实例方法存放在了NSObject.class -> metaClass -> class_data_bits_t -> class_rw_t -> method_array_t -> method_list_t -> method_t -> big中

相关文章

  • 4.iOS底层学习之类的结构

    类的结构 前面我们通过探索了解到一个类实际是一个结构体objc_class,objc_class的实现如下: 可以...

  • iOS底层之类结构分析

    上篇文章: iOS底层之isa走位探索 前言 从上篇文章中我们了解了对象的isa指针的走位逻辑,接下来咱们分析一下...

  • iOS底层探索之类结构

    一、前置知识 CPU 访问内存时需要的是地址,而不是变量名和函数名!变量名和函数名只是地址的一种助记符,当源文件被...

  • iOS底层之类的结构分析

    从iOS底层之isa结构分析及关联类我们探究了类的实例对象的内存结构,对象指针的首地址存储了isa,也就是存储了类...

  • iOS底层探索之类结构下篇

    上篇分析类结构,获取到了属性列表 property_array_t 和方法列表 method_array_t。 实...

  • iOS底层之cache_t探究

    我们在iOS底层之类的结构分析分析了类的内部结构,而类的C/C++底层实际是objc_class结构体,其中包含了...

  • iOS底层原理之类的结构分析

    类的结构和定义 首先跟踪源码,找到Class的的定义,发现其本质为objc_class类型的指针,并且 objc_...

  • iOS底层探索之类的结构(下)

    在之前的几篇博客里面,已经介绍了,类的底层结构,还有isa的走位流程,元类的继承链,对象方法,类方法的存放位置,以...

  • iOS底层探索之类的结构(上)

    回顾 在之前的几篇博客里面,我们知道了对象的本质是结构体(iOS底层探索之对象的本质和类的关联特性initIsa(...

  • iOS底层探索之类的结构(中)

    在上一篇博客里面iOS底层探索之类的结构(上)[https://blog.csdn.net/zjpjay/arti...

网友评论

      本文标题:4.iOS底层学习之类的结构

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