Swift:将类型从属性传递到泛型函数

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

对于我的网络模块,我采用以下协议访问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
        }
    }
}
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)”)
}
}
)
}

你是对的,我混合了函数的两个版本(第一个有泛型,另一个没有)。我更新了代码。谢谢你的回答!我理解为什么不可能。这个问题很相似,也有很好的解释()你是对的,我混合了