iOS - isa、class-rw-t、class-ro-t结构体

简介: iOS - isa、class-rw-t、class-ro-t结构体

源码objc-private.h

struct objc_object {
private:
    isa_t isa;
public:
    // ISA() assumes this is NOT a tagged pointer object
    Class ISA(bool authenticated = false);
    ···
}


isa_t

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    uintptr_t bits;
private:
    // Accessing the class requires custom ptrauth operations, so
    // force clients to go through setClass/getClass by making this
    // private.
    Class cls;
public:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
};


ISA_BITFIELD

# if __arm64__
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
#   if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
#     define ISA_MASK        0x007ffffffffffff8ULL
#     define ISA_MAGIC_MASK  0x0000000000000001ULL
#     define ISA_MAGIC_VALUE 0x0000000000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 0
#     define ISA_BITFIELD                                                      \
        uintptr_t nonpointer        : 1;                                       \
        uintptr_t has_assoc         : 1;                                       \
        uintptr_t weakly_referenced : 1;                                       \
        uintptr_t shiftcls_and_sig  : 52;                                      \
        uintptr_t has_sidetable_rc  : 1;                                       \
        uintptr_t extra_rc          : 8
#     define RC_ONE   (1ULL<<56)
#     define RC_HALF  (1ULL<<7)


上面联合体 isa_t 涉及到一个位域的概念,可以参考《C语言位域(位段)详解》


因为部分数据在存储时候并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。正是基于这种考虑,C语言又提供了一种叫做位域的数据结构。


isa_t 使用了位域,这里 ISA_BITFIELD 位域成员通过跟 bits 相与来取对应的值。 在 ISA_BITFIELD 中定义的参数的含义:


image.png

class_rw_t


objc-runtim-new.h

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 是为了安全操作
    explicit_atomic<uintptr_t> ro_or_rw_ext;
    Class firstSubclass;
    Class nextSiblingClass;
}


class_rw_ext_t 是class_rw_t的拓展


objc-runtime-new.h

struct class_rw_ext_t {
    DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)
    class_ro_t_authed_ptr<const class_ro_t> ro;
    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;
    char *demangledName;
    uint32_t version;
};


class-rw-t里的 methods、properties、protocols是二位数组

class method_array_t : 
public list_array_tt<method_t, method_list_t, method_list_t_authed_ptr>
class property_array_t : 
    public list_array_tt<property_t, property_list_t, RawPtr>
class protocol_array_t : 
    public list_array_tt<protocol_ref_t, protocol_list_t, RawPtr>


image.png


class-ro-t

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif
    union {
        const uint8_t * ivarLayout;
        Class nonMetaclass;
    };
    explicit_atomic<const char *> name;
    // With ptrauth, this is signed if it points to a small list, but
    // may be unsigned if it points to a big list.
    void *baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;
    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;


class_ro_t 里面的 baseMethodList、baseProtocols、ivars、baseProperties 是一维数组,是只读的,包含了类的初始内容,我们拿 baseMethodList 举例子:


image.png

method_t

using MethodListIMP = IMP;
struct method_t {
    static const uint32_t smallMethodListFlag = 0x80000000;
    method_t(const method_t &other) = delete;
    // The representation of a "big" method. This is the traditional
    // representation of three pointers storing the selector, types
    // and implementation.
    struct big {
        SEL name;  //方法、函数名
        const char *types;  //编码(参数类型、返回值类型)
        MethodListIMP imp;  //方法实现,指向方法、函数的指针
    };


方法缓存


Class 内部结构中有个方法缓存(cache_t),调用了方法之后会缓存在里面,他用散列表(哈希表)来缓存曾经调用过的方法,可以提高方法的查找速度。下面是整理出来的重要部分代码:


image.png


这里的散列表的原理就是,通过 @selector(methodName) & _mask 获得一个索引值,通过这个索引就能很快在 buckets 中拿到对应的 bucket_t(key, _imp);当然存放也是一样的方式。


存放:如果生成的索引在 buckets 下已经存在 data 。那么他会把 index - 1,减到零了还没有空闲位置,它会从数组最大值开始继续往前找位置,直到有位置;


获取:在拿到 bucket_t 后,会比较一下 key 与 @selector(methodName) 是否对应,如果不对应,那就回按照存放的那样方式一个一个找。如果存满了,buckets 就会走扩容。


这就是空间换时间。


相关文章
|
存储 Unix 编译器
|
存储 C++
iOS-底层原理 09:类 & isa 经典面试题分析
iOS-底层原理 09:类 & isa 经典面试题分析
165 0
iOS-底层原理 09:类 & isa 经典面试题分析
|
存储 设计模式 编译器
iOS-底层原理 07:isa与类关联的原理
iOS-底层原理 07:isa与类关联的原理
126 0
iOS-底层原理 07:isa与类关联的原理
|
存储 编译器 iOS开发
iOS - isa、superclass指针,元类superclass指向基类本身(下)
本文已同步至掘金:iOS - isa、superclass指针,元类superclass指向基类本身
iOS - isa、superclass指针,元类superclass指向基类本身(下)
|
iOS开发
iOS - isa、superclass指针,元类superclass指向基类本身(上)
本文已同步至掘金:iOS - isa、superclass指针,元类superclass指向基类本身
iOS - isa、superclass指针,元类superclass指向基类本身(上)
|
iOS开发
iOS - OC Struct 结构体
1、结构体的定义与调用 // 定义结构体类型 // 结构体类型名为 MyDate1 struct MyDate1 { int year; int month; ...
936 0
|
iOS开发
iOS - Swift Struct 结构体
1、Struct 的创建 1.1 基本定义 结构体的定义 // 定义结构体数据类型 struct BookInfo { // 每个属性变量都必须初始化 var ID:Int = 0 var Na...
833 0
|
18天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
9天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。