【问题标题】:how prepare API response to use with jsonDecoder in swift如何准备 API 响应以在 swift 中与 jsonDecoder 一起使用
【发布时间】:2019-02-02 20:15:43
【问题描述】:

当我使用 Alamofire 调用 API 并从服务器获取响应时,我想使用来自 json 的“数据”对象

此数据来自 API

{
    "code": 200,
    "hasError": false,
    "data": [
        {
            "userSession": "43a1bd70-26bf-11e9-9ccd-00163eaf6bb4"
        }
    ],
    "message": "ok"
}

我想将data 映射到我的AuthModel

这是我的AuthModel

struct AuthModel: Codable {
    let userSession: String

    enum CodingKeys: String, CodingKey {
        case userSession = "userSession"
    }
}

我编写了这行代码,但它不起作用:

if let responseObject = response.result.value as? Dictionary<String,Any> {
    if let hasError = responseObject["hasError"] as? Bool {
        guard !hasError else { return }
        do {
            let decoder = JSONDecoder()
            let authModel = try decoder.decode(AuthModel.self, from: responseObject["data"])
        } catch {
            print("Parse Error: ",error)
        }
    }
}

这不起作用,因为responseObject["data"] 不是 NSData 类型

无法将“[String : Any]”类型的值转换为预期的参数类型“Data”

【问题讨论】:

    标签: swift codable jsondecoder


    【解决方案1】:

    我认为您的 API 响应是一种模式,表明:

    • 我们有什么问题(错误)吗?
    • 我们有预期的数据吗?

    基于这些,我们可以使用EnumGenerics。例如:

    class ResponseObject<T: Codable>: Codable {
    
        private var code        : Int
        private var hasError    : Bool
        private var message     : String
        private var data        : T?
    
        var result: Result {
            guard !hasError else { return .error(code, message) }
            guard let data = data else { return .error(0, "Data is not ready.") }
            return .value(data)
        }
    
        enum Result {
            case error(Int, String)
            case value(T)
        }
    
    }
    

    我们可以将ResponseObject 与我们预期的data 一起使用:

    let responseString = """
    {
        "code": 200,
        "hasError": false,
        "data": [
            {
                "userSession": "43a1bd70-26bf-11e9-9ccd-00163eaf6bb4"
            }
        ],
        "message": "ok"
    }
    """
    
    class AuthObject: Codable {
        var userSession : String
    
    }
    
    if let jsonData = responseString.data(using: .utf8) {
        do {
            //ResponseObject<[AuthObject]> means: if we don't have error, the `data` object in response, will represent `[AuthObject]`.
            let responseObject = try JSONDecoder().decode(ResponseObject<[AuthObject]>.self, from: jsonData)
    
            //Using ResponseObject.Result Enum: We have error with related code and message, OR, we have our expected data.
            switch responseObject.result {
            case .error(let code, let message):
                print("Error: \(code) - \(message)")
            case .value(let authObjects):
                print(authObjects.first!.userSession)
            }
    
        } catch {
            print(error.localizedDescription)
        }
    }
    

    【讨论】:

      【解决方案2】:

      例如获取Data 响应而不是反序列化的Dictionary

      Alamofire.request(url).responseData { response in
      

      解码

      let decoder = JSONDecoder()
      let authModel = try decoder.decode(AuthModel.self, from: response.data!)
      

      进入这些结构

      struct AuthModel : Decodable {
          let code : Int
          let hasError : Bool
          let message : String
          let data : [Session]
      }
      
      struct Session : Decodable {
          let userSession: String
      }
      

      所有的 CodingKey 都是合成的。

      【讨论】:

      • 发誓,这个 api 响应是所有 API 的模式,所以我不能在我的所有模型中始终使用代码、hasError、消息、数据
      • 我刚刚回答了这个问题。
      猜你喜欢
      • 2018-05-12
      • 2018-05-07
      • 2018-04-24
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多