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
相关产品推荐
相关产品推荐

