Swift泛型问题:如何从调用端传入多种响应类型?
Swift 多状态码响应解码问题解答
1. 自行编写的send函数可能存在的问题
常见问题点包括:
- 泛型约束设计单一,仅支持固定类型解码,无法适配多状态码对应不同结构体的场景,导致编译器无法正确推断解码类型
- 状态码判断与解码逻辑绑定混乱,比如直接尝试将同一数据强制转换为不同类型,引发类型不匹配错误
- 返回类型定义模糊,比如用
Any作为返回值,调用时需要强制类型转换,既不安全也不符合Swift类型安全的设计理念
2. 正确实现与调用方式
最直观且易维护的方案是用关联枚举封装所有可能的成功响应类型,再在send函数中根据状态码分支处理解码逻辑。
代码实现示例
首先定义响应结构体和枚举容器:
// 200状态码对应响应结构体 struct APIOKResponse: Decodable { let message: String let result: [String: String] } // 202状态码对应响应结构体 struct APIAcceptedResponse: Decodable { let taskId: String let processingStatus: String } // 枚举封装所有成功响应类型 enum APISuccessResponse { case ok(APIOKResponse) case accepted(APIAcceptedResponse) } // 自定义API错误类型 enum APIError: Error { case invalidResponse case unhandledSuccessCode(Int) case failedCode(Int) }
重构send函数:
func sendRequest(to url: URL) async throws -> APISuccessResponse { let (data, response) = try await URLSession.shared.data(from: url) guard let httpResp = response as? HTTPURLResponse else { throw APIError.invalidResponse } let decoder = JSONDecoder() switch httpResp.statusCode { case 200: let okResp = try decoder.decode(APIOKResponse.self, from: data) return .ok(okResp) case 202: let acceptResp = try decoder.decode(APIAcceptedResponse.self, from: data) return .accepted(acceptResp) case 200..<300: throw APIError.unhandledSuccessCode(httpResp.statusCode) default: throw APIError.failedCode(httpResp.statusCode) } }
调用方式
通过switch枚举值获取对应类型的响应,无需强制类型转换:
do { let resp = try await sendRequest(to: URL(string: "https://your-api.com/target")!) switch resp { case .ok(let okData): print("200响应:\(okData.message)") case .accepted(let acceptData): print("202响应:任务ID \(acceptData.taskId)") } } catch { print("请求失败:\(error)") }
3. 此需求完全可实现
通过枚举封装多响应类型、状态码分支解码的方案,完全能满足根据不同2xx状态码解码为不同结构体的需求。核心是用一个容器类型(枚举)统一承载所有可能的成功响应,在函数内部完成状态码判断与对应类型的解码,调用方通过枚举拆包即可安全获取具体响应数据,既符合Swift类型安全原则,也便于后续扩展其他2xx状态码的响应类型。
内容的提问来源于stack exchange,提问作者Suyash Medhavi
相关产品推荐
相关产品推荐

