在单个函数中解析远程 JSON 而不在 Swift 中创建模型

Parse remote JSON without creating models in Swift, in a single function

我的应用程序必须通过 HTTPS 请求获取 JSON,然后解析该数据。

我正在寻找的是采用“一个功能统治所有”的方法,就像这样。

func call(endpoint: String) {
   let url = URL(string: "https://example.com/api/"+endpoint)

   URLSession.shared.dataTask(with: url!) { (data, response, error) in
      // Parse JSON here without using a model.
      // Just convert the data into a JSON object and return it
   }
}

在我看来,我遇到的每个示例代码都需要创建一个具有预期值的模型,然后执行此操作:

JSONDecoder().decode(ModelHere.self, from: data)

这意味着我需要为每个端点创建一个新函数。

为什么不为每个端点使用单独的函数?

我有很多端点可以从一个函数中调用。

为每个端点创建一个新函数,将一个单独的模型传递给它,然后从响应中解析数据……代码中有很多垃圾需要筛选。

我敢肯定有更好的方法来做到这一点只是晦涩难懂,或者我错过了。

基本上,我正在寻找这个:

函数需要远程数据来加载视图 -> 触发调用('endpoint/example/') -> call() returns json 对象 -> 函数现在可以获取它需要的数据

多个处理器函数,一个 call() 函数。我希望我说得有道理。

谢谢

这就是 generic 的用途,例如:

您可以将 T 定义为通用类型的日期模型,然后获取它并 return 它完成。使 T 成为可编码的,因此任何符合 codable 的模型都会进行此调用。

func call<T: Codable>(endpoint: String, completion: (T) -> ()) {
   let url = URL(string: "https://example.com/api/"+endpoint)

   URLSession.shared.dataTask(with: url!) { (data, response, error) in
      // Parse JSON here without using a model.
      // Just convert the data into a JSON object and return it
      let model = JSONDecoder().decode(T.self, from: data)
      completion(model)
   }
}

当你调用函数时:

call(endpoint: "something") { model: ModelHere in 
   // Use your model
}

因此您不必为您拥有的每个模型制作单独的函数。

** 代码未经测试,仅供参考

编辑:这是一个带有评论反馈的示例(谢谢@Leo)

private var host = "https://jsonplaceholder.typicode.com/"
    
enum NetworkError: Error {
    case invalidUrl
    case invalidData
    case underlying(_ error: Error)
}

func call<T: Decodable>(endpoint: String,
                        completion: @escaping (Result<T, NetworkError>) -> ()) -> Bool
{
    guard let url = URL(string: host+endpoint) else {
        completion(.failure(.invalidUrl))
        return false
    }
    
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else {
            return completion(.failure(.invalidData))
        }
        do {
            let model = try JSONDecoder().decode(T.self, from: data)
            completion(.success(model))
        } catch let error {
            print(error.localizedDescription)
            completion(.failure(.underlying(error)))
        }
    }.resume()
    return true
}

当您调用函数时:

struct SampleModel: Decodable {
    let id: Int
    let content: String
}

func sample() {
    let isSuccess = call(endpoint: "fetchSampleModelUrl") { (result: Result<[SampleModel], NetworkError>) in
        switch result {
        case .success(let model):
            print("\(model)")
        case .failure(let error):
            print("\(error)")
        }
    }
}