代码之家  ›  专栏  ›  技术社区  ›  heyfrank

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

  •  0
  • heyfrank  · 技术社区  · 7 年前

    对于我的网络模块,我有一个用于访问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:)
    

    但是每次我想使用这个端点时,我都必须传递响应类型。

    我想要实现的是扩展函数 请求和解码 从自身获取响应类型信息, 响应结果类型 属性。

    这有可能吗?

    1 回复  |  直到 7 年前
        1
  •  2
  •   CRD    7 年前

    requestAndDecode Result self.responseResultType

    TestData responseResultType ValidationResponse

    JSONDecoder().decode(ApiResponse<Result>.self ...