Swift中带泛型的可选返回类型网络请求实现问题
问题分析
当前代码存在两个核心问题:
- 泛型参数无法推断:编译器无法将
OutgoingEvent的objectType与函数泛型T建立关联,导致无法自动推导T的类型。 - 类型不匹配:函数返回
T?可选类型,但调用时直接赋值给非可选的User类型,引发类型转换错误。
解决方案
1. 重构枚举,强绑定事件与返回类型
将枚举改为关联值枚举,直接把返回类型作为事件的关联值,让编译器能明确每个事件对应的返回类型,从根源解决类型推断问题:
public enum OutgoingEvent { // 有返回值的事件,关联对应的Codable类型 case user(User.Type) case identification(Identification.Type) // 无返回值的事件,关联Void.Type或单独定义 case logout // ... 更多事件 // 保留原始字符串标识(如果需要与服务器交互用) var rawValue: String { switch self { case .user: return "user" case .identification: return "identification" case .logout: return "logout" // ... 其他事件的rawValue } } } // 给枚举扩展计算属性,统一获取目标类型 extension OutgoingEvent { var targetType: Codable.Type? { switch self { case .user(let type): return type case .identification(let type): return type case .logout: return nil // ... 其他事件处理 } } }
2. 简化泛型函数实现
修改回调版和Async/Await版函数,利用枚举的关联值约束泛型类型:
回调版函数
func sendWithAck<T: Codable>(event: OutgoingEvent, data: [[String : Any]], completion: @escaping (Result<T?, Error>) -> ()) throws { // 检查当前事件是否有目标返回类型 guard let targetType = event.targetType as? T.Type else { // 无返回类型的事件,直接返回nil completion(.success(nil)) return } // 假设已获取服务器返回的result字典 guard let decodedObject = try? decodeFromDict(object: result, type: targetType) else { completion(.failure(ServerCommunicationError.invalidDataFromServer("Could not decode result data."))) return } completion(.success(decodedObject)) }
Async/Await版函数
func sendWithAck<T: Codable>(event: OutgoingEvent, data: [[String : Any]]) async throws -> T? { return try await withCheckedThrowingContinuation { continuation in do { try sendWithAck(event: event, data: data) { result in continuation.resume(with: result) } } catch { continuation.resume(throwing: error) } } }
3. 正确调用函数
现在编译器能从事件的关联值自动推断泛型类型,同时处理可选返回值:
有返回值的场景(如.user事件)
// 推荐用可选绑定处理返回值 if let user = try await ServerService.shared.sendWithAck(event: .user(User.self), data: [updateData]) { // 使用解码后的user对象 } // 若确定服务器必然返回非nil值,可强制解包(谨慎使用) let user: User = try await ServerService.shared.sendWithAck(event: .user(User.self), data: [updateData])!
无返回值的场景(如.logout事件)
// 直接调用忽略返回值即可 try await ServerService.shared.sendWithAck(event: .logout, data: [])
内容的提问来源于stack exchange,提问作者ambassador
相关产品推荐
相关产品推荐

