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

实现URLSessionDelegate的自定义类请求后deinit未调用如何解决

问题根源

这是URLSession和自定义delegate之间的强引用循环问题:

  • 当你使用init(configuration:delegate:delegateQueue:)创建URLSession时,session会强持有传入的delegate对象,也就是你的Request实例
  • 你的代码中没有主动持有创建出来的session实例,也没有在请求结束后调用session的释放方法,session会一直持有delegate,最终导致Request实例永远无法释放
  • request2方法可以正常释放的原因是,你没有传入自定义delegate,使用的是系统默认的全局delegate,不会强持有你的Request实例,请求结束后实例就会正常销毁。

解决方案

方案1:请求完成后主动失效session

持有session实例,在请求回调里主动调用session的失效方法解除强引用:

class Request: NSObject, URLSessionDelegate, URLSessionTaskDelegate{
    // 持有当前session实例
    private var session: URLSession?
    
    func request(){
        let url:URL = URL(string: "https://stackoverflow.com")!
        let config = URLSessionConfiguration.default
        // 赋值给成员变量
        session = URLSession(configuration: config, delegate: self, delegateQueue: .main)
        session?.dataTask(with: url) { [weak self] (data, response, error) in
            print("Received")
            // 请求完成后主动失效session,解除对delegate的强持有
            self?.session?.finishTasksAndInvalidate()
            self?.session = nil
        }.resume()
    }
    
    deinit {
        print("Class deinit...")
    }
}

注意回调中要添加[weak self]避免闭包本身产生额外的强持有。

方案2:复用全局单例session

如果你的业务场景需要频繁发起带客户端证书认证的请求,建议创建全局共享的单例session统一处理所有同配置请求:

  • 单例session生命周期和应用一致,不需要频繁创建销毁,性能开销更低
  • 证书认证的代理逻辑可以统一在单例中实现,避免重复代码

注意事项

  • 所有自定义了delegate的URLSession,不需要使用时都必须调用finishTasksAndInvalidate()(等待现有任务完成后失效)或者invalidateAndCancel()(直接取消所有任务并失效),否则session会一直持有delegate对象造成内存泄漏
  • 不要每次请求都创建新的自定义delegate的URLSession,相同配置的请求尽量复用同一个session。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 18:39:03