Swift:将类型从属性传递到泛型函数
对于我的网络模块,我采用以下协议访问API的不同部分:Swift:将类型从属性传递到泛型函数,swift,generics,swift4,swift-protocols,codable,Swift,Generics,Swift4,Swift Protocols,Codable,对于我的网络模块,我采用以下协议访问API的不同部分: protocol Router: URLRequestConvertible { var baseUrl: URL { get } var route: Route { get } var method: HTTPMethod { get } var headers: [String: String]? { get } var encod
protocol Router: URLRequestConvertible {
var baseUrl: URL { get }
var route: Route { get }
var method: HTTPMethod { get }
var headers: [String: String]? { get }
var encoding: ParameterEncoding? { get }
var responseResultType: Decodable.Type? { get }
}
我采用的枚举如下所示:
enum TestRouter: Router {
case getTestData(byId: Int)
case updateTestData(byId: Int)
var route: Route {
switch self {
case .getTestData(let id): return Route(path: "/testData/\(id)")
case .updateTestData(let id): return Route(path: "/testDataOtherPath/\(id)")
}
}
var method: HTTPMethod {
switch self {
case .getTestData: return .get
case .updateTestData: return .put
}
}
var headers: [String : String]? {
return [:]
}
var encoding: ParameterEncoding? {
return URLEncoding.default
}
var responseResultType: Decodable.Type? {
switch self {
case .getTestData: return TestData.self
case .updateTestData: return ValidationResponse.self
}
}
}
TestRouter.getTestData(byId: 123).requestAndDecode(TestData.self, completion:)
我想使用Codable
对嵌套的Api响应进行解码。每个响应都包含一个令牌和一个结果,其内容取决于请求路由
为了发出请求,我想使用上面enum
中responseResultType
属性中指定的类型
struct ApiResponse<Result: Decodable>: Decodable {
let token: String
let result: Result
}
extension Router {
func asURLRequest() throws -> URLRequest {
// Construct URL
var completeUrl = baseUrl.appendingPathComponent(route.path, isDirectory: false)
completeUrl = URL(string: completeUrl.absoluteString.removingPercentEncoding ?? "")!
// Create URL Request...
var urlRequest = URLRequest(url: completeUrl)
// ... with Method
urlRequest.httpMethod = method.rawValue
// Add headers
headers?.forEach { urlRequest.addValue($0.value, forHTTPHeaderField: $0.key) }
// Encode URL Request with the parameters
if encoding != nil {
return try encoding!.encode(urlRequest, with: route.parameters)
} else {
return urlRequest
}
}
func requestAndDecode(completion: @escaping (Result?) -> Void) {
NetworkAdapter.sessionManager.request(urlRequest).validate().responseData { response in
let responseObject = try? JSONDecoder().decode(ApiResponse<self.responseResultType!>, from: response.data!)
completion(responseObject.result)
}
}
}
但是,每当我想使用这个端点时,我都必须传递响应类型
我想要实现的是,扩展函数requestAndDecode
从自身获取响应类型信息,即responseResultType
属性
这是可能的吗?忽略实际错误报告您在
请求和解码
方面有一个基本问题:它是一个泛型函数,其类型参数在调用站点确定,声明返回结果类型的值
,但它试图返回self.responseResultType类型的值
其值为未知类型
如果Swift的类型系统支持这一点,那么它将需要运行时类型检查、潜在故障,并且您的代码将必须处理这一点。例如,您可以将测试数据
传递给请求和解码
,而响应结果类型
可能是验证响应
将JSON调用更改为:
JSONDecoder().decode(ApiResponse<Result>.self ...
JSONDecoder().decode(ApiResponse.self。。。
并且类型静态匹配(即使Result
的实际类型未知)
您需要重新考虑您的设计。忽略实际错误报告您在
requestAndDecode
方面有一个基本问题:它是一个通用函数,其类型参数在调用站点上确定,该调用站点声明返回Result
类型的值,但它尝试返回self.response类型的值eResultType
的值为未知类型
如果Swift的类型系统支持此功能,则需要运行时类型检查、潜在故障,并且您的代码必须对此进行处理。例如,您可以将TestData
传递给requestAndDecode
,而responseResultType
可能是ValidationResponse
将JSON调用更改为:
JSONDecoder().decode(ApiResponse<Result>.self ...
JSONDecoder().decode(ApiResponse.self。。。
并且类型静态匹配(即使Result
的实际类型未知)
您需要重新考虑您的设计。HTH使用Combine和AlomFire创建一个通用函数。您可以将其用于所有方法(get、post、put、delete)
func-fatchData(requestType:String,url:String,params:[String:Any]?,myType:T.Type,completion:@escaping(Result)->Void){
var method=HTTPMethod.get
开关请求类型{
案例“Get”:
method=HTTPMethod.get
案例“职位”:
方法=HTTPMethod.post
打印(“请求类型\(请求类型)\(方法)”)
案例“付诸表决”:
方法=HTTPMethod.put
违约:
方法=HTTPMethod.delete
}
打印(“url\(url)\(方法)\(AppConstant.headers)”)
task=AF.request(url,方法:method,参数:params,编码:JSONEncoding.default,headers:AppConstant.headers)
.publishDecodable(类型:myType.self)
.sink(receiveCompletion:{(completion)in
交换完成{
案例。完成:
()
案例。失败(let错误):
//完成(.failure(error))
打印(“错误\(错误)”)
}
},接收值:{
中的[弱自我](反应)
打印(“响应\(响应)”)
开关响应。结果{
成功案例(let模型):
完成(.success(model))
打印(“错误成功”)
案例。失败(let错误):
完成(.failure(error))
打印(“错误失败\(error.localizedDescription)”)
}
}
)
}
使用Combine和AlomFire创建一个通用函数。您可以将其用于所有方法(get、post、put、delete)
func-fatchData(requestType:String,url:String,params:[String:Any]?,myType:T.Type,completion:@escaping(Result)->Void){
var method=HTTPMethod.get
开关请求类型{
案例“Get”:
method=HTTPMethod.get
案例“职位”:
方法=HTTPMethod.post
打印(“请求类型\(请求类型)\(方法)”)
案例“付诸表决”:
方法=HTTPMethod.put
违约:
方法=HTTPMethod.delete
}
打印(“url\(url)\(方法)\(AppConstant.headers)”)
task=AF.request(url,方法:method,参数:params,编码:JSONEncoding.default,headers:AppConstant.headers)
.publishDecodable(类型:myType.self)
.sink(receiveCompletion:{(completion)in
交换完成{
案例。完成:
()
案例。失败(let错误):
//完成(.failure(error))
打印(“错误\(错误)”)
}
},接收值:{
中的[弱自我](反应)
打印(“响应\(响应)”)
开关响应。结果{
成功案例(let模型):
完成(.success(model))
打印(“错误成功”)
案例。失败(let错误):
完成(.failure(error))
打印(“错误失败\(error.localizedDescription)”)
}
}
)
}
你是对的,我混合了函数的两个版本(第一个有泛型,另一个没有)。我更新了代码。谢谢你的回答!我理解为什么不可能。这个问题很相似,也有很好的解释()你是对的,我混合了