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

Swift API请求的现代专业实现:逃逸闭包VS代理模式?

Swift发起API请求的现代专业实现:闭包 vs 代理模式

作为Swift初学者,更推荐使用第一种结合Result类型的逃逸闭包写法——这是当前iOS/macOS开发中更现代、简洁的异步API设计方案,代理模式属于较旧的实现方式,如今已很少在新代码中使用。


为什么优先选择逃逸闭包+Result的写法?

  • 代码紧凑,逻辑集中:调用方可以在发起请求的同一处直接处理成功/失败逻辑,无需额外定义代理协议、设置代理,避免代码分散。比如调用示例:

    getTrendingMovies { result in
        switch result {
        case .success(let movies):
            // 直接处理电影数据
        case .failure(let error):
            // 直接处理错误
        }
    }
    

    整个流程一目了然,不用跳转至其他代理方法查看实现。

  • 类型安全清晰:Result<[Movie], Error>明确告知调用方成功时的返回类型、失败时的错误类型,编译器会自动检查类型匹配,避免代理模式中可能出现的类型转换隐患。

  • 内存管理更简单:代理模式容易因循环引用(如self强引用代理对象,代理对象又强引用self)导致内存泄漏;而闭包写法只需通过[weak self]即可轻松规避,内存逻辑更易把控。

  • 贴合Swift异步发展趋势:这种写法是学习Swift 5.5+ async/await的基础,后者本质是该回调模式的语法糖。掌握闭包+Result后,过渡到async/await会非常顺畅,比如用async/await重写示例方法:

    func getTrendingMovies() async throws -> [Movie] {
        guard let url = URL(string: "\(Constants.baseUrl)/trending/all/day?api_key=\(Constants.API_KEY)") else {
            throw URLError(.badURL)
        }
        let (data, response) = try await URLSession.shared.data(from: url)
        guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
            throw URLError(.badServerResponse)
        }
        let results = try JSONDecoder().decode(TrendingMoviesResponse.self, from: data)
        return results.results
    }
    

代理模式的局限性

  • 代码分散,复杂度高:发起请求与处理结果的代码分离,需要定义协议、实现代理方法,对初学者来说,理解代理的生命周期和调用流程需要额外成本。
  • 类型安全不足:代理方法的参数类型往往不够明确,比如didUpdateWeather中的weather若为模糊类型,还需强制转换,易引发错误。
  • 扩展性差:若一个类需处理多种API请求,代理方法会不断膨胀,代码变得臃肿;而闭包写法可为不同请求定义独立的回调逻辑,灵活性更强。

对第一种写法的小优化建议

  • 不要忽略URL创建失败的场景:当前代码中guard let url = ... else {return}直接返回,应通过completion传递错误给调用方:
    guard let url = URL(string: "\(Constants.baseUrl)/trending/all/day?api_key=\(Constants.API_KEY)") else {
        completion(.failure(URLError(.badURL)))
        return
    }
    
  • 校验HTTP响应状态:添加状态码检查,确保是合法的成功响应:
    guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
        completion(.failure(URLError(.badServerResponse)))
        return
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 17:30:34