使用泛型下载的方法需要更多上下文

Method to download using generics asks for more context

我使用泛型编写了一个方法,以使其可重复用于任何类型的下载。它下载 json 个数组和 returns 个通用对象或错误。 这是我的 class 从服务器下载 json 数组:

import Foundation
enum Result<T> {
    case success(T)
    case failure(Error)
}
class LTLNetworkClient: NSObject {

    fileprivate var session : URLSession
    fileprivate var objectTask : URLSessionDataTask?

    override init() {
        let config = URLSessionConfiguration.ephemeral
        config.timeoutIntervalForResource = 5
        config.timeoutIntervalForRequest = 5
        self.session = URLSession.init(configuration: config)
    }

    /**
    Download asynchronously json object from Server and returns it into generic data models
    */
    func getData<K: Codable>(request: URLRequest, completion: @escaping (Result<[K]>) -> Void) {
        let sessionDataTask = URLSession.shared.dataTask(with: request) { (responseData, response, responseError) in
            if let jsonData = responseData {
                let decoder = JSONDecoder()
                do {
                    let response = try decoder.decode([K].self, from: jsonData)
                    let result: Result<[K]> = Result.success(response)
                    completion(result)
                } catch {
                    completion(.failure(error))
                }
            } else if let error = responseError {
                completion(.failure(error))
            } else {
                let error = NSError(domain: "Cannot form jsonData with Response Data", code: 501, userInfo: nil)
                completion(.failure(error))
            }
        }
        sessionDataTask.resume()
    }
}

这就是我调用方法的方式和我得到的错误:

有谁知道如何修复它以及为什么会出现此错误? 提前多谢

这是您的方法声明:

func getData<K: Codable>(request: URLRequest, completion: @escaping (Result<[K]>) -> Void)

这个方法有一个类型参数,K,它只用在completion参数的类型中。当编译器看到对 getData 的调用时,它必须根据您作为 completion.

传递的闭包的参数类型推导出 K 的具体类型

这是你的电话:

networkClient.getData(request: urlRequest) { (result) in
    // Do stuff
}

在此调用中,completion 闭包为 { (result) in }result 的类型是什么?没有关于它的信息,所以编译器只知道 result 必须是 Result<[K]> 类型 K。它无法推导出 K 的具体类型,因此会发出错误。

您可以像这样显式指定类型:

networkClient.getData(request: urlRequest) { (_ result: Result<[SomeConcreteCodableType]>) -> Void in
    // Do stuff
}

其中 SomeConcreteCodableType 是一些符合 Codable 的具体类型。由于 getData 声明中的约束,需要 Codable 一致性。

另一种解决方案是将 getData 更改为采用另一个参数,让调用者直接指定 K

func getArray<K: Codable>(of: K.Type, for request: URLRequest,
    completion: @escaping (Result<[K]>) -> Void) {
    ...
}

然后你这样称呼它:

networkClient.getArray(of: SomeConcreteCodableType.self, for: request) { result in
    // Do stuff
}