Swift中URLSession结合Combine解码JSON数组失败问题解决
问题:Combine的URLSession.dataTaskPublisher无法解码JSON数组
调用服务接口时获取到JSON数组,但无法通过Combine的URLSession.shared.dataTaskPublisher完成解码。项目采用Data、Domain、Presentation分层架构(基于GitHub上的CiMA混合Viper架构)。
原请求代码:
public func getGasStationDiscounts(requestModel: GasStationDiscountsRequestDomainModel) -> CiMAObservable<GasStationDiscountsDomainModel> { guard let url = URL(string: RepositoryConstants.baseURL + String(format: RepositoryConstants.EndPoints.gasStationDiscounts, requestModel.gasStationID)) else { return Fail(error: NSError(domain: "URL Invalid", code: 001, userInfo: nil)).eraseToAnyPublisher() } var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "GET" urlRequest.addValue("application/json", forHTTPHeaderField: "Accept") urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") return URLSession.shared.dataTaskPublisher(for: urlRequest) .map(\.data) .decode(type: GasStationDiscountsDataModel.self, decoder: JSONDecoder()) .map { model -> GasStationDiscountsDomainModel in model.parseToDomainModel() }.eraseToAnyPublisher() }
原可解码模型说明:
原GasStationDiscountsDataModel是针对单个对象的解码模型,但接口实际返回的是该对象组成的JSON数组,导致解码结构不匹配。
已解决!
找到不破坏现有架构的解决方案,调整如下:
可解码模型修改
将原GasStationDiscountsDataModel调整为对应数组中单个元素的结构,确保其能正确解码数组内的每一项数据。
修改后的请求代码
public func getGasStationDiscounts(requestModel: GasStationDiscountsRequestDomainModel) -> CiMAObservable<GasStationDiscountsDomainModel> { guard let url = URL(string: RepositoryConstants.baseURL + String(format: RepositoryConstants.EndPoints.gasStationDiscounts, requestModel.gasStationID)) else { return Fail(error: NSError(domain: "URL Invalid", code: 001, userInfo: nil)).eraseToAnyPublisher() } var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "GET" urlRequest.addValue("application/json", forHTTPHeaderField: "Accept") urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") return URLSession.shared.dataTaskPublisher(for: urlRequest) .map(\.data) .decode(type: [GasStationDiscountsDataModel].self, decoder: JSONDecoder()) .map { model -> GasStationDiscountsDomainModel in let stationDiscountsDomainModel = model.map { model -> StationDiscountDomainModel in model.parseToDomainModel() } return GasStationDiscountsDomainModel(stationDiscounts: stationDiscountsDomainModel) } .mapError { error in print(error.localizedDescription) return error }.eraseToAnyPublisher() }
关键修改点
- 解码类型从
GasStationDiscountsDataModel.self改为[GasStationDiscountsDataModel].self,匹配接口返回的数组结构 - 在map操作中遍历解码后的数组,将每个DataModel转换为对应的DomainModel,再封装到
GasStationDiscountsDomainModel中,适配分层架构要求 - 添加
mapError处理,便于调试解码过程中的错误
内容的提问来源于stack exchange,提问作者coden0w
相关产品推荐
相关产品推荐

