面试题答案
一键面试避免循环引用及内存管理策略
- 使用弱引用(Weak References)
- 在视图控制器之间的相互持有场景中,将其中一方的引用设置为弱引用。例如,若
ViewControllerA
持有ViewControllerB
,同时ViewControllerB
也持有ViewControllerA
,可以将ViewControllerB
中对ViewControllerA
的引用声明为弱引用。在 Swift 中,可以使用weak
关键字,如:
- 在视图控制器之间的相互持有场景中,将其中一方的引用设置为弱引用。例如,若
weak var viewControllerA: ViewControllerA?
- 在 Objective - C 中,使用 `__weak` 修饰符:
__weak ViewControllerA *viewControllerA;
- 弱引用不会增加对象的引用计数,当被引用的对象(如 `ViewControllerA`)释放时,弱引用会自动被设置为 `nil`,从而打破循环引用。
2. 使用无主引用(Unowned References)
- 适用于相互持有且两个对象生命周期相同的场景。在 Swift 中,使用 unowned
关键字。例如:
unowned var viewControllerA: ViewControllerA
- 在 Objective - C 中没有直接对应的关键字,但原理类似,通过不增加引用计数来避免循环引用。不过使用无主引用时要注意,当被引用对象释放后,访问无主引用会导致运行时错误,所以要确保被引用对象先于持有它的对象释放。
3. 合理管理视图控制器的生命周期
- 遵循 iOS 视图控制器的生命周期方法。例如,在 viewDidLoad
中进行初始化操作,在 viewWillDisappear
或 deinit
中清理不需要的引用。在 Swift 中:
deinit {
// 清理对其他视图控制器的强引用
otherViewController = nil
}
- 在 Objective - C 中:
- (void)dealloc {
// 清理对其他视图控制器的强引用
self.otherViewController = nil;
}
- 使用协议(Protocols)和代理(Delegation)模式
- 通过协议定义视图控制器之间的通信方法,将交互逻辑封装在协议方法中。持有关系通过代理来实现,代理通常设置为弱引用。例如,
ViewControllerB
定义一个协议ViewControllerBDelegate
,ViewControllerA
遵循该协议并作为ViewControllerB
的代理。 - 在 Swift 中:
- 通过协议定义视图控制器之间的通信方法,将交互逻辑封装在协议方法中。持有关系通过代理来实现,代理通常设置为弱引用。例如,
protocol ViewControllerBDelegate: AnyObject {
func someMethod()
}
class ViewControllerB: UIViewController {
weak var delegate: ViewControllerBDelegate?
}
class ViewControllerA: UIViewController, ViewControllerBDelegate {
func someMethod() {
// 实现协议方法
}
}
- 在 Objective - C 中:
@protocol ViewControllerBDelegate <NSObject>
- (void)someMethod;
@end
@interface ViewControllerB : UIViewController
@property (weak, nonatomic) id<ViewControllerBDelegate> delegate;
@end
@interface ViewControllerA : UIViewController <ViewControllerBDelegate>
@end
@implementation ViewControllerA
- (void)someMethod {
// 实现协议方法
}
@end
- 使用块(Blocks)时注意循环引用
- 当在视图控制器中使用块来处理逻辑且块中捕获了视图控制器本身时,要使用弱引用或无主引用来避免循环引用。在 Swift 中,可以使用
[weak self]
或[unowned self]
来捕获self
:
- 当在视图控制器中使用块来处理逻辑且块中捕获了视图控制器本身时,要使用弱引用或无主引用来避免循环引用。在 Swift 中,可以使用
let block = { [weak self] in
self?.someMethod()
}
- 在 Objective - C 中,使用 `__weak typeof(self) weakSelf = self;` 来创建弱引用:
__weak typeof(self) weakSelf = self;
self.block = ^{
[weakSelf someMethod];
};
相关技术点总结
- ARC(自动引用计数):iOS 自 iOS 5.0 引入 ARC,它自动管理对象的内存,通过引用计数来决定对象何时释放。理解 ARC 的工作原理对于避免循环引用至关重要,如强引用增加引用计数,弱引用和无主引用不增加引用计数等。
- 对象生命周期:深入理解视图控制器的生命周期,在合适的时机清理引用,确保内存及时释放,避免内存泄漏。
- 设计模式:代理模式和协议的合理使用可以解耦视图控制器之间的直接持有关系,降低循环引用的风险,同时提高代码的可维护性和可扩展性。
- 内存分析工具:使用 Instruments 中的 Leaks 工具来检测内存泄漏和循环引用。通过分析内存快照,可以找出潜在的循环引用对象,及时调整代码进行修复。