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

标签 swift generics nsurlsession

我使用泛型编写了一个方法,以使其可重复用于任何类型的下载。它下载 json 数组并返回一个通用对象或一个错误。 这是我从服务器下载 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()
    }
}

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

enter image description here

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

最佳答案

这是您的方法声明:

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

这个方法有一个类型参数,K , 仅用于 completion 的类型争论。当编译器看到对 getData 的调用时, 它必须为 K 推导出具体类型基于你作为 completion 传递的闭包的参数类型.

这是你的电话:

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 的具体类型. Codable由于 getData 中的约束,需要一致性的声明。

另一种解决方案是更改 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
}

关于swift - 使用泛型下载的方法需要更多上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56382676/

相关文章:

ios - StackView 内的圆角无法正确显示

generics - 将 javac 与 String[] 一起使用时出现意外错误

ios - 为 Alamofire 全局设置超时间隔

ios - 如何在 NSURLSession(Background Session) 事件的情况下测试 Background App Launch?

swift - FIREBASE 4 类型 'StorageReference' 的值没有成员 'put'

ios - 如何自动更新应用程序 iOS 应用程序

ios - Swift - 使用协议(protocol)通过泛型类型初始化类

PHP:动态对象名称

ios - Swift 中的 HTTP 长轮询

swift - 数组修改时的执行闭包