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

Swift中URLSession代理设置优化及API返回数据获取疑问

嘿,我来帮你搞定这两个iOS网络请求里的常见问题——内存泄漏风险和代理方法中获取返回数据的事儿!

一、解决代理初始化导致的内存泄漏问题

你现在的写法确实有两个大问题:一是创建了一个全新的CreateAccountViewController实例作为代理,这个实例既没有加入视图层级,也没有被其他对象合理持有,但URLSession会强引用它的代理,导致这个多余的VC实例无法被释放,进而引发内存泄漏;二是这个新建的VC根本不是你当前正在显示的那个,它的回调对你的业务逻辑完全没用!

优化方案

我们需要让当前的CreateAccountViewController实例作为代理,同时避免循环引用:

  1. 修改APICalls类,让它接受代理参数
    不要在API工具类里自己创建VC实例,而是让外部传入符合协议的代理对象:
class APICalls {
    static func performLoginRequest(with request: URLRequest, delegate: URLSessionDataDelegate) {
        // 创建临时URLSession,不需要持有它——dataTask会持有session直到任务完成
        let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)
        session.dataTask(with: request).resume()
    }
}
  1. 让当前VC遵守协议并传递自身作为代理
    在CreateAccountViewController中声明遵守相关协议,调用API时传入self:
class CreateAccountViewController: UIViewController, URLSessionDataDelegate, URLSessionTaskDelegate {
    // 点击登录按钮的方法
    @IBAction func loginButtonTapped(_ sender: UIButton) {
        // 构造你的loginRequest...
        APICalls.performLoginRequest(with: loginRequest, delegate: self)
    }
    
    // 后续实现代理方法...
}

这样既不会创建多余的VC实例,也能保证回调正确触发,从根源上避免了不必要的内存泄漏。

二、在代理方法中获取API返回的数据

你只实现了任务完成的代理方法,但要拿到返回数据,还需要处理数据接收的过程——因为网络数据可能分块返回,我们需要自己拼接完整数据:

  1. 在VC中声明变量存储接收的数据
class CreateAccountViewController: UIViewController, URLSessionDataDelegate, URLSessionTaskDelegate {
    private var receivedData = Data() // 用来拼接分块返回的数据
    // ...其他代码...
}
  1. 实现数据接收的代理方法
    这个方法会在每次收到数据块时触发,我们把数据拼接到receivedData中:
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
    receivedData.append(data)
}
  1. 在任务完成方法中处理完整数据
    现在receivedData就是API返回的完整数据了,可以进行解析:
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    // 处理完数据后清空,避免干扰下次请求
    defer { receivedData.removeAll() }
    
    if let error = error {
        print("登录请求失败:\(error.localizedDescription)")
        // 这里可以更新UI提示用户失败,注意要切到主线程
        DispatchQueue.main.async {
            self.showErrorToast(message: "登录失败,请检查网络")
        }
        return
    }
    
    // 解析数据(假设返回的是JSON格式)
    do {
        let loginResponse = try JSONDecoder().decode(LoginResponse.self, from: receivedData)
        // 登录成功,处理业务逻辑(比如跳转首页、保存token)
        DispatchQueue.main.async {
            self.navigateToHomePage()
        }
    } catch {
        print("数据解析失败:\(error.localizedDescription)")
        DispatchQueue.main.async {
            self.showErrorToast(message: "数据解析错误")
        }
    }
}

额外推荐:更简洁的闭包回调方式

如果没有特殊需求(比如监听上传/下载进度、自定义证书验证),推荐使用URLSession的闭包回调方式,不用处理代理,代码更紧凑,还能轻松避免循环引用:

// 在APICalls中实现闭包版本的登录方法
class APICalls {
    static func login(with request: URLRequest, completion: @escaping (Result<Data, Error>) -> Void) {
        URLSession.shared.dataTask(with: request) { data, _, error in
            if let error = error {
                completion(.failure(error))
                return
            }
            guard let data = data else {
                let noDataError = NSError(domain: "LoginError", code: -1, userInfo: [NSLocalizedDescriptionKey: "未获取到返回数据"])
                completion(.failure(noDataError))
                return
            }
            completion(.success(data))
        }.resume()
    }
}

// 在VC中调用
@IBAction func loginButtonTapped(_ sender: UIButton) {
    APICalls.login(with: loginRequest) { [weak self] result in
        guard let self = self else { return } // 避免循环引用
        DispatchQueue.main.async {
            switch result {
            case .success(let data):
                do {
                    let loginResponse = try JSONDecoder().decode(LoginResponse.self, from: data)
                    self.navigateToHomePage()
                } catch {
                    self.showErrorToast(message: "数据解析错误")
                }
            case .failure(let error):
                self.showErrorToast(message: error.localizedDescription)
            }
        }
    }
}

这种方式不用管理代理和数据拼接,代码更易读,内存安全也更有保障。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 20:33:15