You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS内存管理疑问:闭包场景下为何未触发循环引用?

iOS内存管理疑问解答:为何预期的循环引用未导致内存泄漏?

我了解ARC会通过对象的强引用计数来管理内存,当强引用计数变为0时对象会被释放,但以下代码让我产生了困惑:

final class SecondVC: UIViewController {
    let titleLabel: UILabel = UILabel()
    let network = Network()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .red
        self.view.addSubview(titleLabel)
        
        network.makeCall {
            self.titleLabel.text = "Title"
        }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.navigationController?.popViewController(animated: true)
    }
    
    deinit {
        print("SecondVC deinit called")
    }
}

final class Network {
    func makeCall(completion: @escaping () -> Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            
        }
    }
    
    deinit {
        print("Network deinit called")
    }
}

我的理解是:SecondVC对Network持有强引用,同时Network通过闭包捕获了SecondVC的强引用,且completion回调从未被调用,按道理强引用计数不会变为0,但两者的deinit方法都被执行了。

我的问题是:是否存在内存泄漏?为何理论上不应被释放的对象却执行了deinit?


解答

不存在内存泄漏,核心原因如下:

  • Network的makeCall方法虽然接收了@escaping类型的completion闭包,但方法内部并没有将这个completion保存到类属性、全局变量或其他长期持有它的容器中。
  • 当makeCall方法执行完毕后,completion闭包就失去了所有强引用,它之前捕获的self(即SecondVC实例)的引用也随之被释放。
  • 因此SecondVC和Network之间并未形成持续的循环引用,两者的强引用计数最终都能降为0,所以各自的deinit方法会被正常调用。

内容的提问来源于stack exchange,提问作者artyom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 15:40:25