Swift中如何创建兼容不同Endpoint类型的EndpointMapping数组?
解决泛型EndpointMapping无法存入同一数组的问题
核心原因
EndpointMapping<T>是泛型结构体,不同Endpoint实现对应不同的T,因此生成的EndpointMapping实例属于不同具体类型。Swift数组要求元素类型统一,直接声明[EndpointMapping]会触发编译错误。解决关键是通过类型擦除,用统一的非泛型协议包装异构泛型实例。
具体实现方案
1. 定义非泛型的统一接口协议
创建不包含关联类型的协议,封装请求并更新模型的核心行为:
protocol AnyEndpointMapping { func fetchAndUpdate(model: DashboardResponseModel, group: DispatchGroup) }
2. 让泛型EndpointMapping遵循该协议
修改原EndpointMapping<T>实现上述协议,把请求、解析、赋值逻辑封装到协议方法内:
struct EndpointMapping<T: Endpoint>: AnyEndpointMapping { let endpoint: T let keyPath: WritableKeyPath<DashboardResponseModel, T.ModelType?> func fetchAndUpdate(model: DashboardResponseModel, group: DispatchGroup) { group.enter() // 替换为你实际的网络请求方法 performRequest(with: endpoint) { result in defer { group.leave() } switch result { case .success(let parsedModel): model[keyPath: keyPath] = parsedModel case .failure(let error): // 根据需求处理错误,如日志上报 print("请求\(endpoint.path)失败: \(error.localizedDescription)") } } } // 示例网络请求方法,需替换为项目实际实现 private func performRequest(with endpoint: T, completion: @escaping (Result<T.ModelType, Error>) -> Void) { // 这里实现网络请求、JSON解码逻辑 // 比如用URLSession发送请求,解码为T.ModelType } }
3. 使用统一类型数组管理所有映射
现在可以声明[AnyEndpointMapping]类型的数组,自由添加不同端点的映射实例:
func loadDashboardData(completion: @escaping (DashboardResponseModel) -> Void) { let dashboardModel = DashboardResponseModel() let dispatchGroup = DispatchGroup() let endpointMappings: [AnyEndpointMapping] = [ EndpointMapping(endpoint: CurrenciesEndpoint(), keyPath: \.currency), EndpointMapping(endpoint: UserEndpoint(), keyPath: \.user), EndpointMapping(endpoint: BalanceEndpoint(), keyPath: \.balance) ] endpointMappings.forEach { mapping in mapping.fetchAndUpdate(model: dashboardModel, group: dispatchGroup) } dispatchGroup.notify(queue: .main) { completion(dashboardModel) } }
额外说明
- 类型擦除的本质是把泛型特有的类型信息(如
T.ModelType的解码、keyPath的类型)隐藏在结构体内部,对外仅暴露统一的行为接口。 - 如果需要扩展功能(如自定义超时、请求优先级),可以在
AnyEndpointMapping协议中添加对应方法,或在EndpointMapping中增加属性支持。
内容的提问来源于stack exchange,提问作者Burak Akyalçın
相关产品推荐
相关产品推荐

