当前ViewController与ViewModel代码是否产生强引用循环?weak还是unowned?
强引用循环分析 & 解决方案
好问题!咱们来仔细拆解你的代码,看看是否存在强引用循环,以及对应的处理方式:
1. 当前代码是否存在强引用循环?
答案是:不存在。我们来梳理一下引用关系:
ViewController持有一个强引用的viewModel属性:var viewModel = ViewModel()ViewModel的showAlert是一个可选闭包,你在viewDidLoad中给它赋值时,使用了[weak self]捕获了ViewController的弱引用
此时的引用链是:ViewController → 强引用 → ViewModel,而闭包对 ViewController 的引用是弱引用,不会形成「互相强引用」的闭环,所以不会产生内存泄漏。
如果去掉 [weak self],情况就不一样了:闭包会强引用 ViewController,加上 ViewController 本身强引用 ViewModel,就会形成 ViewController ↔️ ViewModel 的强引用循环,导致两者都无法被系统释放,造成内存泄漏。
2. 若存在强引用循环,该用 weak 还是 unowned?
这取决于被捕获对象(也就是这里的 ViewController)是否可能在闭包执行期间变为 nil:
- 用
weak:当被捕获对象可能被释放(比如ViewController可能被从导航栈弹出、或者被销毁)时,weak是更安全的选择。它会自动将引用置为nil,避免野指针访问。你的场景里,ViewController作为UI控制器,显然存在被释放的可能,所以weak是正确的选择。 - 用
unowned:只有当你能100%确定被捕获对象在闭包执行期间永远不会被释放时,才考虑使用unowned。它不会自动置为nil,如果对象被释放后访问,会直接触发运行时崩溃。比如一个对象的闭包是该对象的一部分,且两者生命周期完全绑定的场景。
补充代码示例(正确的弱引用写法)
你的代码已经是正确的写法了,再贴一遍方便对照:
class ViewController { var viewModel = ViewModel() func viewDidLoad() { self.viewModel.showAlert = { [weak self] in self?.alert() } } func alert() { // alert logic } } class ViewModel { var showAlert: (() -> Void)? }
内容的提问来源于stack exchange,提问作者Savan Kavaiya
相关产品推荐
相关产品推荐

