swift - Swift:将类型从属性传递给泛型函数
问题描述
对于我的网络模块,我采用了这个协议来访问 API 的不同部分:
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
}
}
}
我想Codable
用于解码嵌套的 Api 响应。每个响应都包含一个令牌和一个结果,其内容取决于请求路由。
为了发出请求,我想使用上面responseResultType
属性中 指定的类型enum
。
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
方法中它会抛出一个编译器错误(Cannot invoke 'decode' with an argument list of type '(Any.Type, from: Data)'
)。我不能那样用ApiResponse<self.responseResultType!>
。
我可以使这个函数通用并像这样调用它:
TestRouter.getTestData(byId: 123).requestAndDecode(TestData.self, completion:)
但是每次我想使用这个端点时,我都必须传递响应类型。
我想要实现的是扩展函数requestAndDecode
从它本身,responseResultType
属性中获取响应类型信息。
这可能吗?
解决方案
忽略实际的错误报告,您有一个根本问题requestAndDecode
:它是一个泛型函数,其类型参数在调用站点确定,它被声明为返回一个类型的值,Result
但它试图返回一个self.responseResultType
其值为未知类型的类型值.
如果 Swift 的类型系统支持这一点,它将需要运行时类型检查、潜在的失败,并且您的代码将不得不处理它。例如,您可以传递TestData
给requestAndDecode
whileresponseResultType
可能是ValidationResponse
...
将 JSON 调用更改为:
JSONDecoder().decode(ApiResponse<Result>.self ...
并且类型静态匹配(即使实际类型Result
未知)。
你需要重新考虑你的设计。高温高压
推荐阅读
- android - 如何在 Android Studio 中全局创建列表数组并在列表视图中显示内容?
- google-cloud-platform - 在“选择”列表中看不到组织,甚至在组织中拥有“组织管理员”权限
- kql - kusto查询语言中如何将查询结果数据转换为json格式
- javascript - 反应钩子从数组中删除项目并将其添加到另一个数组
- javascript - 在 JavaScript 中用前导零填充数字?
- ssl - 在为一个 strpi 项目运行 npm i 时,证书链中的自签名证书
- c# - Xamarin Android 中应用程序数据的路径
- excel - 如何防止excel将值转换为日期?
- php - laravel 将金额添加到循环中的下一个父级
- json - jq - 在一行中从 json 表中检索特定列的值