OC底层探索(五):类的结构

isa分析到元类

  • 我们知道Classobjc_class*类型也就是一个指针,objc_class 是继承与 objc_object, 所以Class 也是有isa
typedef struct objc_class *Class;

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

struct objc_class: objc_object {
  // isa
...
}

Class isa
复制代码

lldb分析isa

  • 通过对象的isa可以得到类,那类的isa又存的是什么呢,还以可以通过lldb打印来查看结果

image.png

  • 根据上面的打印可以看出,isa(–>) 对象–>类–>元类–>根元类–>根元类
  • 类的isa 存到的就是元类,不需要通过mask掩码去得到,只有对象的才是 nonpointer。因为只有对象才有引用计数,弱引用等
  • 也可以得出其实类也是一个是对象,这也应证万物接对象

teacher是继承person, 通过lldb查看一下tacherisa
image.png

  • 可以得出teacher元类也是指向根元类

继承关系的isa

image.png

  • ->表示继承 meta 表示元类
  • WLWTeacher -> WLWPerson -> NSObject -> nil
  • WLWTeacher(meta) -> WLWPerson(meta) -> NSObject(meta) -> NSobject -> nil
  • 元类也是有继承的关系的,会继承父类的元类,一直到根元类
  • 根元类的继承根类

NSProxy 的isa与继承

image.png

  • NSProxy是遵守NSObject协议的,也是根类,所以他跟NSOject根类一样,只是根类换成的NSProxy
  • 所以NSProxyNSObjec是同级的,都是根类

代码打印

    // NSObject实例对象
    NSObject *object1 = [NSObject alloc];
    // NSObject类
    Class class = object_getClass(object1);
    // NSObject元类
    Class metaClass = object_getClass(class);
    // NSObject根元类
    Class rootMetaClass = object_getClass(metaClass);
    // NSObject根根元类
    Class rootRootMetaClass = object_getClass(rootMetaClass);
    NSLog(@"\n%p 实例对象\n%p 类\n%p 元类\n%p 根元类\n%p 根根元类",object1,class,metaClass,rootMetaClass,rootRootMetaClass);
    
    // LGPerson元类
    Class pMetaClass = object_getClass(LGPerson.class);
    Class psuperClass = class_getSuperclass(pMetaClass);
    NSLog(@"%@ - %p",psuperClass,psuperClass);
    
    // LGTeacher -> LGPerson -> NSObject
    // 元类也有一条继承链
    Class tMetaClass = object_getClass(LGTeacher.class);
    Class tsuperClass = class_getSuperclass(tMetaClass);
    NSLog(@"%@ - %p",tsuperClass,tsuperClass);
    
    // NSObject 根类特殊情况
    Class nsuperClass = class_getSuperclass(NSObject.class);
    NSLog(@"%@ - %p",nsuperClass,nsuperClass);
    // 根元类 -> NSObject
    Class rnsuperClass = class_getSuperclass(metaClass);
    NSLog(@"%@ - %p",rnsuperClass,rnsuperClass);
复制代码

苹果官方

image.png

总结

  • 万物皆对象,类只有一块地址,相当于系统帮你创建了一个单例对象,然后我们基于类这个对象继承再开辟的新的内存创建对象
  • 元类也有继承关系,元类继承父类的元类
  • 根元类继承根类,根类继承nil
  • 对象 isa -> 类 isa -> 元类 isa -> 根元类 isa -> 根元类
  • 根类 isa -> 根元类 isa

源码分析类的结构

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
    .....
    .....
  }
复制代码
  • 由于类的结构里有很多的方法,我们先分析 类结构里的成员变量
  • 类里有4个成员变量,

Class ISA

  • 第一个是隐藏的Class ISA,继承自objc_object, 我们也知道其指向元类, 是一个指针,所以是 8字节

superClass

  • 第二个 superClass 很明显是指向父类, 也是个指针8字节

cache_t cache

  • 第三个cache_t cache,这个非常的重要,很好理解是缓存,具体缓存了什么,还需要进一步探索
    • 查看一下cache_t结构体
    struct cache_t {
    private:
    // buckets 的指针/首地址 , explicit_atomic<T> 确定类型 允许转换, uintptr_t = unsigned long 无符号长整型
    explicit_atomic<uintptr_t>  _bucketsAndMaybeMask; // 8字节
    // 联合体,内存共享,成员变量互斥
    union {
        struct {
            // mask_t: mac: uint32_t 
            // 掩码
            explicit_atomic<mask_t>    _maybeMask; //4字节
         #if __LP64__
            // 标记
            uint16_t                   _flags; //2字节
         #endif
            //已占用数量
            uint16_t                   _occupied; //2字节
        };
        // 指针,原始的规则缓存
        explicit_atomic<preopt_cache_t *> _originalPreoptCache; // 8字节
    };
    复制代码
    • 可以算出cache_t大小是16字节

class_data_bits_t

  • 第四个class_data_bits_t bits ,里放了些数据根据注释可以看出是 class_rw_t *加上 rr/alloc 的自定义 flags,源码也可与看粗 其占用8字节
struct class_data_bits_t {
// friend 友元
friend objc_class;

// Values are the FAST_ flags above.
uintptr_t bits; // 8字节
。。。。。
。。。。。
复制代码

lldb分析类的结构

image.png

  • 根据cache_t的内部结构可以得出0x000000019a7033e0_bucketsAndMaybeMask, 0x0000801900000000是那个联合体
  • class_data_bits_t 就是其内部的bits

类的bits数据分析

  • 我们知道如何找到bits, 我们在源码环境中将其打印出来
  • 在非源码环境没有class_data_bits_t类型,无法打印其结构,但我们可以通过仿写底层代码来实现打印

image.png

class_rw_t *data() const {
    return bits.data();
}
复制代码
  • 通过lldb打印出内存地址,再通过objc_class里提供的方法我们拿到$46 = class_rw_t
  • firstSubClass 是运行时,赋值的
  • 可以看出类是个树状结构

class_rw_t (dirty memory)

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; // 兄弟类
复制代码
class_rw_t 的 falgs 标记

// Values for class_rw_t->flags
// These are not emitted by the compiler and are never used in class_ro_t.
// Their presence should be considered in future ABI versions.
// class_t->data is class_rw_t, not class_ro_t
#define RW_REALIZED           (1<<31)
// class is unresolved future class
#define RW_FUTURE             (1<<30)
// class is initialized
#define RW_INITIALIZED        (1<<29)
// class is initializing
#define RW_INITIALIZING       (1<<28)
// class_rw_t->ro is heap copy of class_ro_t
#define RW_COPIED_RO          (1<<27)
// class allocated but not yet registered
#define RW_CONSTRUCTING       (1<<26)
// class allocated and registered
#define RW_CONSTRUCTED        (1<<25)
// available for use; was RW_FINALIZE_ON_MAIN_THREAD
// #define RW_24 (1<<24)
// class +load has been called
#define RW_LOADED             (1<<23)
#if !SUPPORT_NONPOINTER_ISA
// class instances may have associative references
#define RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS (1<<22)
#endif
// class has instance-specific GC layout
#define RW_HAS_INSTANCE_SPECIFIC_LAYOUT (1 << 21)
// class does not allow associated objects on its instances
#define RW_FORBIDS_ASSOCIATED_OBJECTS       (1<<20)
// class has started realizing but not yet completed it
#define RW_REALIZING          (1<<19)

#if CONFIG_USE_PREOPT_CACHES
// this class and its descendants can't have preopt caches with inlined sels
#define RW_NOPREOPT_SELS      (1<<2)
// this class and its descendants can't have preopt caches
#define RW_NOPREOPT_CACHE     (1<<1)
#endif

// class is a metaclass (copied from ro)
#define RW_META               RO_META // (1<<0)
复制代码
  • class_rw_t的内部一些方法

// 获取ro clean memory
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);
}

// 设置ro clean memory
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};
    }
}

复制代码
properties()

image.png

  • 成员变量不会存在这里,只有属性property
methods()

image.png

image.png

  • 方法里有属性生成的set, get方法
  • 没有类方法,也就是所谓的+号方法,存有-号方法
  • types = 0x0000000100003df7 "v24@0:8@16", 第一个v表示返回值void, 下边是对照表

image.png

protocols()

image.png

image.png

image.png

  • protocols底层是protocol_t 结构体
class_ro_t
ivars

image.png

  • 成员变量存在了 class_ro_tivars里,
  • 并且里面也存储了属性生成的带有下划线_的变量
baseProperties

image.png

  • ro baseProperties 里的值与 rw propertires一样
baseMethodList

ro
image.png
rw
image.png

  • 可以看出这连个地址是一样的, 所里存的方法是一样的
baseProtocols

rw
image.png
ro
image.png

  • 地址也是一样的
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享