96SEO 2026-05-05 19:03 0
在 iOS 开发的江湖里Objective-C 一直以其独特的动态特性著称。而支撑这门语言“动态”灵魂的,正是那个让无数初级开发者望而生畏,却又让高级工程师爱不释手的底层机制——Runtime。你是否想过当我们写下 这行简单的代码时编译器到底在背地里Zuo了什么?为什么我们Ke以在 Category 中“凭空”添加属性?又是如何在不修改源码的情况下拦截系统方法的?这一切的谜底,dou藏在 Runtime 这套庞大的 C 语言 API 之中。

说实话,Runtime 并不是什么高不可攀的黑魔法,它geng像是一把手术刀,Neng让你深入到 App 的骨骼和血脉中进行精细的手术。随着 Swift 生态的日益成熟,虽然 Swift 强调静态安全,但Runtime 依然是不可或缺的核心技Neng。今天我们就抛开那些晦涩难懂的学术定义,用Zui接地气的方式,彻底搞懂 iOS Runtime。
一、 揭开面纱:Runtime 到底是什么?简单来说Runtime 就是 Objective-C 的运行时环境。它是一套主要由 C 语言和汇编编写而成的 API 库,充当了 OC 代码与底层硬件之间的桥梁。对于 C++ 或 Java 这种静态语言而言,函数的调用在编译期就Yi经确定了地址;但 OC 不同,它是一门动态语言,将hen多决策推迟到了运行时才决定。
这就好比你去餐厅点菜,静态语言像是你提前一周预订了套餐,服务员上菜时不会出错;而 OC 则像是你现场kan着菜单点菜,甚至厨师Ke以根据当天的食材动态调整Zuo法。Runtime 就是那个负责“接单、找厨师、上菜”的后台管理系统。
在底层结构中,OC 的对象本质上dou是一个 objc_object 结构体,而这个结构体里只有一个核心成员——isa 指针。这个 isa 就像是对象的身份证,告诉系统:“我属于哪个类”。而类本身,在底层则是 objc_class 结构体的实例,里面存储了方法列表、属性列表、协议列表以及父类的指针。
// 底层对象的本质
struct objc_object {
Class isa; // 指向该对象所属的类
};
// 类的底层结构
struct objc_class {
Class isa; // 指向元类
Class super_class; // 指向父类
const char *name; // 类名
long version; // 版本信息
struct objc_method_list *methodLists; // 方法列表
struct objc_ivar_list *ivars; // 成员变量列表
struct objc_cache *cache; // 方法缓存,提升查找效率
struct objc_protocol_list *protocols; // 协议列表
};
kan到这里你可Neng会问,为什么要有 cache?这就涉及到性Neng优化了。毕竟Ru果每次调用方法dou要去遍历庞大的方法列表,那 App 的流畅度简直没法kan。Runtime hen聪明,它会将Zui近调用过的方法缓存起来下次调用时直接命中缓存,速度飞快。
在 OC 中,我们习惯用方括号 来调用方法。但在编译阶段,这段代码会被翻译成 C 语言的函数调用:objc_msgSend)。这就是 Runtime 消息传递机制的起点。
这个过程其实是一场精密的“寻宝游戏”,其流程大致如下:
查缓存系统通过对象的 isa 指针找到类,并在类的 cache 中查找方法。Ru果找到了直接执行,流程结束。这是Zui快的一步。
查方法列表Ru果缓存没命中,系统就会去遍历类的方法列表。找到了就执行,并顺便把方法存入缓存,以备后用。
沿父类链查找Ru果当前类没找到,系统会沿着 super_class 指针一层层往上找,直到找到 NSObject 或者根类为止。
消息转发Ru果一路找到了祖宗十八代还是没找到这个方法,程序并不会立马崩溃,而是进入了 Runtime Zui著名的“消息转发”三阶段。
为了演示这个过程,我们Ke以手动调用 objc_msgSend,这通常用于一些极端的性Neng优化场景:
#import
// 定义一个简单的类
@interface Person : NSObject
- sayHello:name;
@end
@implementation Person
- sayHello:name {
NSLog;
}
@end
// 使用示例
Person *person = init];
// 1. 正常的 OC 调用
;
// 2. 手动调用 Runtime API
SEL sel = @selector;
)objc_msgSend);
消息转发的三道防线
当消息发送失败后Runtime 给了我们三次“补救”的机会,这就像是给 App 上了三道保险,防止它因为一个未实现的方法而闪退。
第一道防线:动态方法解析系统会调用 +resolveInstanceMethod:或 +resolveClassMethod:。在这里你Ke以通过 class_addMethod 动态地给类添加一个方法的实现。这通常用于动态创建属性或处理可选协议的方法。
@implementation Person
+ resolveInstanceMethod:sel {
if ) {
// 动态添加一个 C 函数作为实现
// "v@:" 表示返回值 void,参数 id 和 SEL
class_addMethoddynamicMethodIMP, "v@:");
return YES;
}
return ;
}
// 动态添加的 C 函数实现
void dynamicMethodIMP {
NSLog;
}
@end
第二道防线:快速转发
Ru果第一道防线没拦住系统会调用 -forwardingTargetForSelector:。这个方法允许你将消息转发给另一个对象。这就像是你说“这事我办不了你去找老王吧”,然后把消息直接扔给老王处理。
@implementation Person
- forwardingTargetForSelector:aSelector {
if ) {
// 转发给 Student 对象处理
return init];
}
return ;
}
@end
第三道防线:标准转发
Ru果快速转发也没处理,那就只Neng动用重武器了——-methodSignatureForSelector: 和 -forwardInvocation:。这一步需要你手动生成方法签名,并创建 NSInvocation 对象来处理消息。虽然繁琐,但它Neng让你修改消息的参数、返回值,甚至实现多播代理。
@implementation Person
// 1. 生成方法签名
- methodSignatureForSelector:aSelector {
if ) {
return ;
}
return ;
}
// 2. 处理转发
- forwardInvocation:anInvocation {
Student *student = init];
if {
;
} else {
;
}
}
@end
三、 Runtime 的实战利器:Method Swizzling 与 Associated Objects
理解了原理,我们来kankan Runtime 在实际开发中是如何大显身手的。其中Zui著名的两个应用场景,莫过于 Method Swizzling和 Associated Objects。
1. Method Swizzling:偷天换日的黑魔法Method Swizzling 允许我们在运行时交换两个方法的实现。这意味着,当你调用 A 方法时实际执行的却是 B 方法的代码。这在 AOP领域简直是神器,比如无侵入式的埋点统计、UI 兼容性适配、防崩溃处理等。
通常,我们会在 Category 的 +load 方法中进行交换,因为 +load 在类加载时就会调用,且只调用一次时机Zui早,Zui安全。
#import
@implementation UIViewController
+ load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = ;
// 获取原始方法
SEL originalSelector = @selector;
Method originalMethod = class_getInstanceMethod;
// 获取自定义方法
SEL swizzledSelector = @selector;
Method swizzledMethod = class_getInstanceMethod;
// 交换两个方法的实现
method_exchangeImplementations;
});
}
// 自定义的实现方法
- trk_viewDidLoad {
// 注意:这里调用 trk_viewDidLoad 其实是在调用原始的 viewDidLoad
;
// 添加埋点逻辑
NSLog);
}
@end
这里有个细节需要注意:在 trk_viewDidLoad 内部,我们调用的 其实Yi经指向了原始的 viewDidLoad 实现。这就是 Swizzling 的奇妙之处,逻辑有点绕,但一旦习惯了就非常顺手。
我们知道,OC 的 Category虽然好用,但有一个硬伤:不Neng直接添加实例变量。Ru果你想在分类里存点数据,以前可Neng得用全局字典,既麻烦又不优雅。
Runtime 提供的关联对象 API 完美解决了这个问题。它允许我们将一个对象“关联”到另一个对象上,就像它原本就有这个属性一样。
#import
@interface UIButton
@property NSString *customName;
@end
@implementation UIButton
// 定义关联对象的 Key,使用 static const 确保唯一性
static const void *kCustomNameKey = &kCustomNameKey;
- setCustomName:customName {
// 参数:对象、Key、值、内存管理策略
// OBJC_ASSOCIATION_COPY_NONATOMIC 相当于 @property
objc_setAssociatedObject;
}
- customName {
return objc_getAssociatedObject;
}
@end
// 使用
UIButton *btn = ;
btn.customName = @"登录按钮";
NSLog;
关于内存管理策略,这里有个对照表,大家Ke以根据需要选择:
OBJC_ASSOCIATION_ASSIGN // 相当于 @property
OBJC_ASSOCIATION_RETAIN_NONATOMIC // 相当于 @property
OBJC_ASSOCIATION_COPY_NONATOMIC // 相当于 @property
OBJC_ASSOCIATION_RETAIN // 相当于 @property
OBJC_ASSOCIATION_COPY // 相当于 @property
四、 Runtime 与 Swift 的爱恨情仇
随着 Swift 成为 iOS 开发的主力,hen多人担心 Runtime 会过时。其实大可不必。Swift 虽然追求静态安全和性Neng,但它依然保留了与 OC 的互操作性,甚至也支持一定的动态特性。
只要你在 Swift 方法前加上 @objc 或 dynamic 关键字,这个方法就Ke以被 Runtime 动态调用。这对于那些需要同时支持 OC 和 Swift 的混合项目来说至关重要。
import ObjectiveC
class SwiftPerson: NSObject {
@objc dynamic func sayHello {
print
}
}
// 动态获取类并调用
if let cls = NSClassFromString as? SwiftPerson.Type {
let person = cls.init
let sel = NSSelectorFromString
person.perform
}
此外Swift 还提供了 @dynamicMemberLookup 等特性,虽然实现机制与 OC Runtime 不同,但在动态处理成员变量的思路上,可谓异曲同工。在 Apple 推出的新框架中,依然Nengkan到 Runtime 思想的影子。
Runtime 不仅仅是一堆 API,它geng是一种思维方式。当你习惯了从运行时的角度去审视代码,你会发现hen多原本棘手的问题dou有了新的解题思路。
当然Runtime 也是一把双刃剑。滥用 Swizzling 可Neng会让代码逻辑变得难以追踪,滥用关联对象可Neng导致内存泄漏。但只要我们在理解原理的基础上谨慎使用,它绝对是 iOS 工程师进阶路上的神兵利器。
希望这篇文章Neng帮你拨开 Runtime 的迷雾。接下来建议你找个开源项目,kankan它们是如何运用 Runtime 来提升开发效率的。毕竟纸上得来终觉浅,绝知此事要躬行。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback