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

Swift中URLSession任务存属性时的内存泄漏差异疑问

问题

研究Swift内存泄漏场景时遇到一个疑惑:创建新的UIViewController并调用fetchAPI函数,将未启动的URLSession下载任务存入控制器属性后关闭该控制器,发现控制器的deinit函数未被调用(存在内存泄漏),代码如下:

func fetchAPI() {
    let url = URL(string: "https://www.google.com")!
    let task = URLSession.shared.downloadTask(with: url) { _, _, _ in
        DispatchQueue.main.async {
            print(self.view.description)
        }
    }
    self.vcTask = task
}

但如果调用fetchAPI时同时调用task.resume()启动任务,再关闭UIViewController,控制器的deinit函数能正常被调用(无内存泄漏),代码如下:

func fetchAPI() {
    let url = URL(string: "https://www.google.com")!
    let task = URLSession.shared.downloadTask(with: url) { _, _, _ in
        DispatchQueue.main.async {
            print(self.view.description)
        }
    }
    self.vcTask = task
    task.resume() // start downloading
}

原本认为将任务存入UIViewController属性且回调中使用self会形成循环引用导致内存泄漏,但为何启动任务后不会出现内存泄漏?

分析与解答

核心原因在于未启动的URLSessionTask和已启动完成的Task对self的持有逻辑完全不同:

  • 未启动的Task的持有链
    当你创建downloadTask但不调用resume()时:

    • UIViewController通过属性vcTask强持有Task
    • 未启动的Task会强持有其回调闭包,而闭包中直接引用了self(UIViewController)
    • 同时,URLSession.shared会一直强持有未启动的Task(Task属于该Session,未启动状态下Session不会释放它)
      这就形成了闭环的循环引用链:UIViewController → vcTask → 闭包 → UIViewController,再加上Session对Task的额外强持有,整个引用链无法被ARC自动回收,所以控制器的deinit不会触发。
  • 启动并完成后的Task的持有变化
    当调用task.resume()后:

    • Task启动执行,完成(或失败、被取消)后,URLSession.shared会主动释放对该Task的强引用
    • 同时,Task在回调闭包执行完毕后,也会释放对闭包的强引用
      此时循环引用链被彻底打破:UIViewController虽仍持有vcTask,但Task不再持有闭包,Session也不再持有Task,当控制器被关闭时,没有其他外部强引用持有它,ARC会正常回收控制器,触发deinit。

另外要注意:无论Task是否启动,最稳妥的做法是在闭包中使用弱引用([weak self]),从根源上避免循环引用风险,示例代码如下:

let task = URLSession.shared.downloadTask(with: url) { [weak self] _, _, _ in
    DispatchQueue.main.async {
        guard let self = self else { return }
        print(self.view.description)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 04:15:39