2-Runtime objc_object objc_class

本文深入解析Objective-C运行时的核心概念,包括基类NSObject、对象结构体objc_object、类结构体objc_class等关键组件的内部实现细节,并探讨了方法缓存与类数据位的巧妙设计。
一 NSObject

NSObject是OC 中的基类,除了NSProxy其他都继承自NSObject

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
二 对象结构体 objc_object

在运行时,类的对象被定义为objc_object 类型,就是对象结构体

在OC 中每一个对象都是一个结构体,结构体都包含了一个isa 成员变量。

根据isa的定义可以知道,类型为isa_t 类型的

struct objc_object {
private:
    isa_t isa;
}

isa_t 的定义是什么?

是一个union的结构对象,类似于C++结构体,其内部可以定义为成员变量和函数,是一个联合类型。

三 类结构体 objc_class

类也是一个对象,类的结构体objc_class 是继承自objc_object的,具备对象的所有特征。

从源码可以看出

bits结构体的data 函数,获取到class_rw_t 指针

1 supercalss 当前类的父类

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() { 
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }
 	
}

// class_rw_t 定义
class_rw_t* data() {
	return (class_rw_t *)(bits & FAST_DATA_MASK);
}

 

2 cache 是处理已经调用过方法的缓存

在运行时方法调用的流程,当我们调用一个方法的时候,先不去类的方法列表去寻找,而是先去cache 中去寻找。

如果方法已经存在,直接return掉。

struct cache_t {
    // 数组 存放方法的SEL 和 IMP
    struct bucket_t *_buckets;
    // 用作掩码
    mask_t _mask;
	// 当前已缓存的方法数。即数组中已使用了多少位置。
    mask_t _occupied;
}

typedef uintptr_t cache_key_t;

struct bucket_t {
private:
    cache_key_t _key;
    IMP _imp;

public:
    inline cache_key_t key() const { return _key; }
    inline IMP imp() const { return (IMP)_imp; }
    inline void setKey(cache_key_t newKey) { _key = newKey; }
    inline void setImp(IMP newImp) { _imp = newImp; }

    void set(cache_key_t newKey, IMP newImp);
};
 

3 class_data_bits_t

只有一个成员bits ,对类的操作几乎就是围绕它展开。

作用:64的bits,来存储与类有关的信息。

怎么存储呢?

其中包含了各种异或来说明class 的属性。把这些信息复合在一起,仅用一个UINT指针bits来表示。当需要取出这些信息时,用需要的对应以FAST_前缀开头和结尾的标志对掩码bits做按位与操作。

位 在内存中的三种排列方式

64 位

0123-46
FAST_IS_SWIFTFAST_HAS_DEFAULT_RRFAST_REQUIRES_RAW_ISAFAST_DATA_MASK
struct class_data_bits_t {

    // Values are the FAST_ flags above.
    uintptr_t bits;
 
    public:
    class_rw_t* data() {
        // FAST_DATA_MASK 代表着一块存储结构 
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
    void setData(class_rw_t *newData)
    {
        assert(!data()  ||  (newData->flags & (RW_REALIZING | RW_FUTURE)));
        // Set during realization or construction only. No locking needed.
        // Use a store-release fence because there may be concurrent
        // readers of data and data's contents.
        uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
        atomic_thread_fence(memory_order_release);
        bits = newBits;
    }

}
四 class_rw_t
四 class_ro_t 和 class_rw_t

在编译之后,class_data_bits_t 的指针指向的是一个class_ro_t的地址,这个结构体是不可变的只读。

在运行时,才会通过realizeClass 函数将bits指向class_rw_t。

在程序开始运行只有初始化Class,在这个过程中,回吧编译器存在class_data_bits_t中的class_ro_t 取出来,然后创建class_rw_t,并且把ro 赋值给rw,最后把rw 设置给bits,替代之前bits 中存储的ro。

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
    uint32_t reserved;
	const uint8_t * ivarLayout;
	const char * name;
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    
    const ivar_list_t * ivars;
    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
}


struct class_rw_t {
    uint32_t flags;
    uint32_t version; 
    // 类不可修改的原始核心
    const class_ro_t *ro;
    // 下面三个array,method,property, protocol,可以被runtime 扩展,如Category
    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;
    
    // 和继承相关的东西
    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值