iOS底层原理系列03-Objective-C运行时机制

1. Runtime 架构详解与内部工作机制

OC 作为一门动态语言,其强大的灵活性主要源于其底层运行时系统(Runtime)。Runtime 系统实质上是一套 C 和汇编语言编写的 API,它作为 OC 与底层系统之间的桥梁,使得 OC 拥有了动态特性。

OC Runtime 系统的核心架构由以下几个关键组件构成:

  1. Class 结构体:用于表示类的基本单元
  2. Object 结构体:表示对象实例
  3. Method 结构体:封装方法信息
  4. IMP 函数指针:指向方法的实际实现
  5. SEL 选择器:方法的唯一标识符

在 iOS 开发中,我们日常编写的 OC 代码最终都会转换为 Runtime 的 C 函数调用。这一转换过程由编译器和运行时系统共同完成。

在这里插入图片描述

现在,让我们来看一下 Runtime 系统中最核心的几个数据结构的定义:

// objc 对象结构
struct objc_object {
    Class isa;  // 指向类的指针
};

// 类结构
struct objc_class {
    Class isa;  // 元类指针
    Class super_class;  // 父类指针
    const char *name;  // 类名
    long version;  // 版本信息
    long info;  // 类信息
    long instance_size;  // 实例大小
    struct objc_ivar_list *ivars;  // 实例变量列表
    struct objc_method_list **methodLists;  // 方法列表
    struct objc_cache *cache;  // 方法缓存
    struct objc_protocol_list *protocols;  // 协议列表
};

// 方法结构
struct objc_method {
    SEL method_name;  // 方法选择器
    char *method_types;  // 方法类型编码
    IMP method_imp;  // 方法实现函数指针
};

Runtime 系统的核心工作原理围绕着这些结构体展开,通过它们实现了 OC 语言的动态特性,包括动态类型、动态绑定以及动态加载等功能。

2. 消息传递机制

2.1 objc_msgSend实现原理

OC 中的方法调用本质上是消息传递过程。当我们编写如下代码时:

[object method:argument];

编译器会将其转换为:

objc_msgSend(object, @selector(method:), argument);

objc_msgSend 函数是 Runtime 系统的核心,它的基本实现原理如下:

  1. 获取对象的 isa 指针,找到对应的类
  2. 在类的方法缓存中查找方法
  3. 如果缓存中找不到,则在方法列表中查找
  4. 如果当前类中找不到,则沿着继承链向上查找
  5. 如果继承链上都没有找到,则进入消息转发流程
  6. 找到方法后,执行对应的 IMP 函数指针

objc_msgSend 主要使用汇编语言实现,以保证最高的性能。其伪代码逻辑大致如下:

id objc_msgSend(id self, SEL _cmd, ...) {
    if (self == nil) return nil;
    
    // 查找实现
    IMP imp = lookUpImpOrForward(self, _cmd);
    
    // 执行方法实现,传递所有参数
    return imp(self, _cmd, ...);
}

2.2 方法查找流程分析

objc_msgSend 函数开始查找方法实现时,会按照以下顺序执行查找:
在这里插入图片描述

  1. 缓存查找:首先在对象所属类的方法缓存(cache)中查找,缓存使用哈希表实现,查找速度非常快。
  2. 当前类查找:如果缓存中没有找到,则在类的方法列表(methodLists)中查找。这个过程相对较慢,因为需要遍历方法列表。
  3. 父类链查找:如果在当前类中没有找到方法,则沿着继承链向上查找父类的方法,同样遵循缓存优先的原则。
  4. 动态解析:如果继承链上都没有找到对应方法,则会触发动态方法解析流程,调用 +resolveInstanceMethod:+resolveClassMethod: 方法。
  5. 消息转发:如果动态解析未能解决问题,则进入完整的消息转发流程。

方法查找的源码实现位于 objc-runtime-new.mm 文件中的 lookUpImpOrForward 函数:

IMP lookUpImpOrForward(id obj, SEL sel, Class cls, int behavior) {
    // 缓存查找
    if (cache_getI
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值