使用泛型下载的方法需要更多上下文
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
}
我使用泛型编写了一个方法,以使其可重复用于任何类型的下载。它下载 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
}