在我的应用程序中,几个控制器的代码结构非常相似,差异很小,因此为了优化,我决定为这些控制器创建一个基础,并从该基础继承每个特定的控制器。
我具有用于发送网络请求和处理响应的功能,我将响应结构作为参数传递给此函数,以便该函数向我返回现成的响应结构。每个此类结构均为Decodable
。
这种结构的示例:
struct APIAnswerUserActivity: Decodable {
let status: String
let code: Int?
let data: [UserActivity]?
let total: Int?
}
用于网络请求的功能,Decodable.Protocol
类型的对象(结构)被接受为jsonType
参数:
public func networkRequest<T: Decodable> (
url: String,
timeout: Double = 30,
method: URLMethods = .GET,
data: [String : String]? = nil,
files: [URL]? = nil,
jsonType: T.Type,
success: @escaping (T) -> Void,
failure: @escaping (APIError) -> Void
) -> URLSessionDataTask { ... }
主控制器中有几个参数,我要通过子控制器中的覆盖来覆盖,这些参数之一应该是类型为Decodable
的对象,以便常规功能正确接收数据。响应的JSON结构非常相似,但仍然略有不同,由于数据仍然有些不同,因此无法为其创建通用结构。
如果在主控制器中执行此操作:
public var decodableType: Decodable.Type {
return APIAnswerUserActivity.self
}
这将起作用,并且可以重新定义类型,但是网络功能不接受此类型,它需要Decodable.Protocol
对象。如果为变量decodable.Protocol
指定了类型decodableType
,则不再可以添加APIAnswerUserActivity.self
,当调用networkRequest函数时,该值将被静默接受。
在这种情况下怎么办?我希望我能够正确正确地阐明问题的实质。谢谢!
@@ладиславАртемьев,由于您尚未共享采用Decodable
类的代码,我仍然不确定我是否完全理解该问题。但是问题似乎与如何传递Decodable
类有关。
我希望以下内容可以帮助阐明如何将正确的约束强加给泛型,以及如何声明变量。您可以将其粘贴到操场上并进行实验。
import Foundation
struct FakeToDo: Decodable {
var userId: Int
var id: Int
var title: String
var completed: Bool
}
enum URLMethods {
case GET
case POST
}
func networkRequest<T: Decodable> (
url: String,
timeout: Double = 30,
method: URLMethods = .GET,
data: [String : String]? = nil,
files: [URL]? = nil,
jsonType: T.Type,
success: @escaping (T) -> Void,
failure: @escaping (Error) -> Void
) -> URLSessionDataTask {
let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { (data, response, error) in
if error != nil {
failure(error!)
return
}
guard let data = data else { return }
let decoder = JSONDecoder()
guard let value = try? decoder.decode(T.self, from: data) else { return }
// get back on the main queue for UI
DispatchQueue.main.async {
success(value)
}
})
return task
}
class Example<T> where T: Decodable {
let type: T.Type
init(_ type: T.Type) {
self.type = type
}
public var decodableType: T.Type {
return type
}
}
let decodableType = Example(FakeToDo.self).decodableType
let url = "https://jsonplaceholder.typicode.com/todos/1"
let task = networkRequest(url: url, jsonType: decodableType,
success: { value in print(value) },
failure: { error in print(error) })
task.resume()