iOS runtime 机制解读(结合 objc4 源码)

本文深入探讨了Objective-C的Runtime机制,结合objc4源码详细解释了消息传递的过程,包括objc_object、objc_class、元类、Method、SEL、IMP、缓存和Category等概念。此外,文章还介绍了消息转发的流程,包括动态方法解析、备用接收者和完整的消息转发机制。最后,文章展示了Runtime在实际应用中的场景,如关联对象、方法添加和替换、KVO实现以及MJExtension和NSCoding的自动归档解档等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

欢迎访问我的博客原文

Runtime 是指将数据类型的确定由编译时推迟到了运行时。它是一套底层的纯 C 语言 API,我们平时编写的 Objective-C 代码,最终都会转换成 runtime 的 C 语言代码。

不过,runtime API 的实现是用 C++ 开发的(源码中的实现文件都是 .mm 文件)。

为了更全面地理解 runtime 机制,我们结合最新的objc4 源码来进行解读。

消息传递

我们知道 Objective-C 是面向对象开发的,而 C 语言则是面向过程开发,这就需要将面向对象的类转变成面向过程的结构体

在 Objective-C 中,所有的消息传递中的“消息”都会被编译器转化为:

id objc_msgSend ( id self, SEL op, ... );

比如执行一个对象的方法:[obj foo];,底层运行时会被编译器转化为:objc_msgSend(obj, @selector(foo));

那么方法内部的执行流程究竟是怎么样的呢?我先来了解一些概念。

概念

objc_object

Objective-C 对象是由 id 类型表示的,它本质上是一个指向 objc_object 结构体的指针。

typedef struct objc_object *id;

union isa_t {
   
   
    isa_t() {
   
    }
    isa_t(uintptr_t value) : bits(value) {
   
    }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
   
   
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

struct objc_object {
   
   
private:
    isa_t isa;
// public & private method...
}

我们看到 objc_object 的结构体中只有一个对象,就是指向其类的 isa 指针。

当向一个对象发送消息时,runtime 会根据实例对象的 isa 指针找到其所属的类。

objc_class

Objective-C 的类是由 Class 类型来表示的,它实际上是一个指向 objc_class 结构体的指针。

typedef struct objc_class *Class;

objc_class 结构体中定义了很多变量:

struct objc_class : objc_object {
   
   
    // 指向类的指针(位于 objc_object)
    // Class ISA;
    // 指向父类的指针
    Class superclass;
    // 用于缓存指针和 vtable,加速方法的调用
    cache_t cache;             // formerly cache pointer and vtable
    // 存储类的方法、属性、遵循的协议等信息的地方
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    // class_data_bits_t 结构体的方法,用于返回class_rw_t 指针()
    class_rw_t *data() {
   
    
        return bits.data();
    }
    // other methods...
}

struct class_rw_t {
   
   
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint32_t version;

    const class_ro_t *ro;
    
    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;
    
    Class firstSubclass;
    Class nextSiblingClass;
    
    char *demangledName;

#if SUPPORT_INDEXED_ISA
    uint32_t index;
#endif
    // other methods
}

objc_class 继承自 objc_object,因此它也拥有了 isa 指针。除此之外,它的结构体中还保存了指向父类的指针、缓存、实例变量列表、方法列表、遵守的协议等。

元类

元类(metaclass)是类对象的类,它的结构体和 objc_class 是一样的。

由于所有的类自身也是一个对象,我们可以向这个对象发送消息,比如调用类方法。那么为了调用类方法,这个类的 isa 指针必须指向一个包含类方法的一个 objc_class 结构体。而类对象中只存储了实例方法,却没有类方法,这就引出了元类的概念,元类中保存了创建类对象以及类方法所需的所有信息。

为了更方便理解,举个例子:

- (void)eat;    // 一个实例方法
+ (void)sleep;  // 一个类方法

// 那么实例方法需要由类对象来调用:
[person eat];
// 而类方法需要由元类来调用:
[Person sleep];

假如 person 对象也能调用 sleep 方法,那我们就无法区分它调用的就究竟是 + (void)sleep; 还是 - (void)sleep;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值