04-主题|内存管理@iOS-ARC详解

5 阅读3分钟

本文介绍 ARC(Automatic Reference Counting,自动引用计数) 的机制、strong/weak/unowned 等所有权修饰符、编译器如何插入引用计数代码,以及常见应用场景与注意事项。前置知识见 03-引用计数与MRC详解


ARC 是什么(简要介绍)

ARCAutomatic Reference Counting:在编译期由编译器根据代码中的所有权修饰符(如 strong、weak)和代码结构,自动插入 retain、release、autorelease 等调用,开发者不再手写这些方法。底层仍然使用与 MRC 相同的引用计数规则,只是「谁在何时 +1/-1」由编译器决定。ARC 自 iOS 5 / WWDC 2011 引入,现为 Objective-C 与 Swift 的推荐方式;Swift 仅支持 ARC。使用 ARC 时仍需理解强引用与弱引用循环引用自动释放池 的释放时机,见 05-AutoreleasePool与RunLoop06-weak与循环引用


一、ARC 是什么

1.1 定义

  • ARC 是编译期特性:编译器根据所有权修饰符代码结构,在合适位置自动插入 retain、release、autorelease 等调用。
  • 与 MRC 使用同一套引用计数规则,对象生命周期语义一致;开发者不再手写 retain/release,减少遗漏与错误。

1.2 与 MRC 对比

维度MRCARC
谁写 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(默认)、weakunowned 与 OC 语义对应;闭包捕获列表 [weak self] / [unowned self] 用于避免循环引用。
  • 详见 Swift 官方 - Automatic Reference Counting

参考文献