【问题标题】:Returning generic type from a URLRequest dataTask从 URLRequest dataTask 返回泛型类型
【发布时间】:2020-02-26 12:25:38
【问题描述】:

我正在尝试构建一个通用函数,以便在 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 没有指定其返回类型是原因,但我不明白为什么。 是否有可能为这段代码提供足够的上下文来编译?

【问题讨论】:

    标签: swift swift-playground


    【解决方案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
         ...
    }
    

    另外,在guard 语句中添加return

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

    【讨论】:

      【解决方案2】:

      你必须声明

      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
          ...
      }
      

      而不是不方便的致命错误添加一个更好的结果类型,以便能够在调用方法之前也返回错误并捕获错误的 URL

      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()
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-11
        • 2017-06-07
        相关资源
        最近更新 更多