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 经典面试题分析
163 0
iOS-底层原理 09:类 & isa 经典面试题分析
|
存储 设计模式 编译器
iOS-底层原理 07:isa与类关联的原理
iOS-底层原理 07:isa与类关联的原理
118 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; ...
930 0
|
iOS开发
iOS - Swift Struct 结构体
1、Struct 的创建 1.1 基本定义 结构体的定义 // 定义结构体数据类型 struct BookInfo { // 每个属性变量都必须初始化 var ID:Int = 0 var Na...
829 0
|
1月前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
98 1
|
1月前
|
设计模式 安全 Swift
探索iOS开发:打造你的第一个天气应用
【9月更文挑战第36天】在这篇文章中,我们将一起踏上iOS开发的旅程,从零开始构建一个简单的天气应用。文章将通过通俗易懂的语言,引导你理解iOS开发的基本概念,掌握Swift语言的核心语法,并逐步实现一个具有实际功能的天气应用。我们将遵循“学中做,做中学”的原则,让理论知识和实践操作紧密结合,确保学习过程既高效又有趣。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你打开一扇通往iOS开发世界的大门。