本文介绍 ARC(Automatic Reference Counting,自动引用计数) 的机制、strong/weak/unowned 等所有权修饰符、编译器如何插入引用计数代码,以及常见应用场景与注意事项。前置知识见 03-引用计数与MRC详解。
ARC 是什么(简要介绍)
ARC 即 Automatic Reference Counting:在编译期由编译器根据代码中的所有权修饰符(如 strong、weak)和代码结构,自动插入 retain、release、autorelease 等调用,开发者不再手写这些方法。底层仍然使用与 MRC 相同的引用计数规则,只是「谁在何时 +1/-1」由编译器决定。ARC 自 iOS 5 / WWDC 2011 引入,现为 Objective-C 与 Swift 的推荐方式;Swift 仅支持 ARC。使用 ARC 时仍需理解强引用与弱引用、循环引用及 自动释放池 的释放时机,见 05-AutoreleasePool与RunLoop、06-weak与循环引用。
一、ARC 是什么
1.1 定义
- ARC 是编译期特性:编译器根据所有权修饰符与代码结构,在合适位置自动插入 retain、release、autorelease 等调用。
- 与 MRC 使用同一套引用计数规则,对象生命周期语义一致;开发者不再手写 retain/release,减少遗漏与错误。
1.2 与 MRC 对比
| 维度 | MRC | ARC |
|---|---|---|
| 谁写 retain/release | 开发者手写 | 编译器自动插入 |
| 所有权表达 | 通过方法名约定 + 手写调用 | 通过变量/属性修饰符(strong/weak 等) |
| autorelease | 手写 autorelease | 编译器在需要时插入 |
| 循环引用 | 需手写 weak 或打破引用 | 同样需用 weak/unowned 打破 |
二、所有权修饰符(Objective-C)
2.1 常见修饰符
| 修饰符 | 含义 | 引用计数影响 |
|---|---|---|
| __strong(默认) | 强引用,拥有对象 | 赋值时 retain,离开作用域或置 nil 时 release |
| __weak | 弱引用,不拥有对象 | 不增加引用计数;对象释放时自动置为 nil |
| __unsafe_unretained | 不保留引用,不拥有 | 不增加引用计数;对象释放后不置 nil,可能野指针 |
| __autoreleasing | 通过引用传入并在 autorelease 池中释放 | 用于 out 参数等场景 |
2.2 属性与修饰符对应
| 属性声明 | 默认修饰符 | 说明 | |
|---|---|---|---|
strong | __strong | 强引用,常用 | |
weak | __weak | 弱引用,打破循环或非拥有关系 | |
copy | __strong(拷贝语义) | 设值时 copy,用于 block、NSString 等;深浅拷贝与 copy 语义见 [11-深浅拷贝与内存](11-主题 | 内存管理@iOS-深浅拷贝与内存.md) |
assign | __unsafe_unretained | 不持有,多用于基本类型或需避免循环时(非对象慎用) |
三、ARC 下的典型场景
3.1 强引用与释放时机
// 局部变量:离开作用域时自动 release
- (void)foo {
NSObject *obj = [[NSObject alloc] init]; // 强引用,rc=1
// 使用 obj
} // 作用域结束,编译器插入 release,obj 可能 dealloc
3.2 弱引用与循环引用
// 两个对象互相强引用 → 循环引用,都无法释放
// 解决:一方改为 weak
@interface Child : NSObject
@property (nonatomic, weak) Parent *parent; // 弱引用父类
@end
3.3 Block 中的循环引用
// self → block → self,形成循环
__weak typeof(self) wself = self;
self.block = ^{
__strong typeof(wself) sself = wself;
[sself doSomething];
};
详见 06-weak与循环引用。Block 的三种类型(全局/栈/堆)、copy 语义与 MRC/ARC 差异见 10-Block内存管理。
四、流程图:ARC 编译期插入示意
flowchart TB
subgraph 源码
A[strong 赋值]
B[变量离开作用域]
end
subgraph 编译器插入
A --> C[插入 retain]
B --> D[插入 release]
end
五、Swift 中的 ARC
- Swift 仅支持 ARC,无 MRC。
- strong(默认)、weak、unowned 与 OC 语义对应;闭包捕获列表
[weak self]/[unowned self]用于避免循环引用。 - 详见 Swift 官方 - Automatic Reference Counting。