从URLRequest dataTask返回泛型类型

时间:2020-02-26 12:25:38

标签: swift swift-playground

我正在尝试构建一个泛型函数,以在URLSession的dataTask完成后返回给定类型的数组。

我有这个可破坏物品:

struct Todo: Hashable, Codable, Identifiable {
    var id: Int
    var title: String
    var completed: Bool
}

此功能:

func loadFrom<T: Decodable>(url: String, memberType: T, completionHandler: (T?) -> Void) {
    guard let url = URL(string: url) else {
        completionHandler(nil)
    }

    URLSession.shared.dataTask(with: url) {data, response, error in
        guard let data = data else {
            fatalError("No data returned")
        }

        do {
            let decoder = JSONDecoder()
            let results = try decoder.decode(T.self, from: data)

            completionHandler(results)
        }catch {
            fatalError("Couldn't parse data")
        }
    }.resume()
}

loadFrom(url: "https://jsonplaceholder.typicode.com/todos?completed=true", memberType: Todo) {response in
    ...
}

错误:Swift Scratchpad.playground:61:88:错误:参数类型'Todo.Type'与预期的类型'Decodable'不符

我已经看到了类似的问题,这些问题表明编译器无法综合Decodable协议要求一致性的方法,但是构建分配给Decodable类型而不是将其指定为参数的相似方法有效:

func loadFile<T: Decodable>(file: String) -> T {
...
}

var todos: [Todo] = loadFile(file: "todos.json")
print(todos[0].title) => "The todo title"

我认为我的loadFrom没有指定返回类型的事实是原因,但是我不明白为什么。 是否可以提供足够的上下文来编译此代码?

2 个答案:

答案 0 :(得分:1)

loadFrom(url:memberType:completionHandler:)方法中,

1。。使用 T.Type 代替T作为memberType

的数据类型

2。。将 @escaping 添加到completionHandler

func loadFrom<T: Decodable>(url: String, memberType: T.Type, completionHandler: @escaping ((T?)->())) 

调用类似方法

loadFrom(url: "https://jsonplaceholder.typicode.com/todos?completed=true", memberType: Todo.self) {response in
     ...
}

还要在return语句中添加guard

guard let url = URL(string: url) else {
    completionHandler(nil)
    return //here...
}

答案 1 :(得分:0)

您必须声明

func loadFrom<T: Decodable>(url: String, memberType: T.Type, completionHandler: @escaping (T?) -> Void) {

并调用它

loadFrom(url: "https://jsonplaceholder.typicode.com/todos?completed=true", memberType: Todo.self) {response in
    ...
}

与麻烦的致命错误相比,它添加了更好的结果类型,以便能够在调用方法之前也返回错误并捕获错误的网址

func loadFrom<T: Decodable>(url: URL, memberType: T.Type, completionHandler: @escaping (Result<T,Error>) -> Void) {
    URLSession.shared.dataTask(with: url) {data, _, error in
        if let error = error {
            completionHandler(.failure(error))
        } else {
           completionHandler( Result{ try JSONDecoder().decode(T.self, from: data!)})
        }
    }.resume()
} 
相关问题