
1) 【一句话结论】在iOS开发中,处理循环引用的核心是通过弱引用(weak)或无主引用(unowned)打破对象间的强引用循环,避免内存泄漏,具体场景如视图控制器与视图、模型对象间的引用,需根据对象是否可能为nil选择合适引用类型。
2) 【原理/概念讲解】循环引用是指两个或多个对象互相持有对方,形成强引用(strong)循环,导致系统无法通过引用计数为0释放这些对象,从而造成内存泄漏。类比:两个朋友A和B,A说“我等你吃饭”,B说“我等你吃饭”,谁都不先放话,结果两人都等不到对方,内存(吃饭机会)一直存在。在iOS中,对象通过强引用互相持有,引用计数增加,当所有强引用消失时,引用计数才为0,循环中每个对象的引用计数永远不会为0,因此无法释放。
3) 【对比与适用场景】
| 引用类型 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| weak | 弱引用,不增加引用计数 | 对象可能为nil,适用于可能被释放的对象 | 当一个对象可能被释放(如视图控制器在视图消失时被释放),持有它的对象用weak | 必须在对象被释放前设置,否则可能访问nil |
| unowned | 无主引用,不增加引用计数 | 对象不会为nil,适用于对象生命周期与持有者一致 | 当一个对象的生命周期与持有者完全一致,不会在持有者存在时被释放 | 如果对象提前释放,访问会导致野指针(crash) |
4) 【示例】
假设有一个网络请求的代理对象(如NSURLSessionDelegate),视图控制器持有代理,代理持有视图控制器,形成循环。伪代码:
ViewController.h:
@interface ViewController : UIViewController <NSURLSessionDelegate>
@property (nonatomic, weak) NSURLSessionDelegate *delegate; // 视图控制器持有代理(weak)
URLSessionDelegate.h:
@interface MyDelegate : NSObject <NSURLSessionDelegate>
@property (nonatomic, strong) ViewController *viewController; // 代理持有视图控制器(strong)
当视图控制器销毁时,代理还持有它,导致循环。解决:视图控制器用weak持有代理,代理用unowned持有视图控制器(假设视图控制器不会在代理存在时被释放)。
5) 【面试口播版答案】
在iOS开发中,循环引用是指两个或多个对象互相持有,导致内存无法释放。常见场景比如视图控制器与它管理的视图模型、或者网络请求的代理对象。处理方法是使用弱引用(weak)或无主引用(unowned)打破循环。比如,视图控制器持有代理用weak,代理持有视图控制器用unowned(如果视图控制器不会在代理存在时被释放)。核心是避免强引用循环,确保当一个对象被释放时,另一个对象不再持有它。
6) 【追问清单】
__weak __typeof(self)weakSelf = self;),或者使用__block(需注意线程安全)。7) 【常见坑/雷区】