如何准备 API 响应以在 swift 中与 jsonDecoder 一起使用

Posted

技术标签:

【中文标题】如何准备 API 响应以在 swift 中与 jsonDecoder 一起使用【英文标题】:how prepare API response to use with jsonDecoder in swift 【发布时间】: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”

【问题讨论】:

【参考方案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、消息、数据 我刚刚回答了这个问题。

以上是关于如何准备 API 响应以在 swift 中与 jsonDecoder 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django API GET 请求中与 websocket 通信?

如何设置正确的 Ruby 版本以在 Aptana 3 中与我的 Rails 5 项目一起使用?

如何使用 Swift 使用 API 响应

如何在 Node.js 中与 Net 建立持久连接?

如何设置 QWebChannel JS API 以在 QWebEngineView 中使用?

Swift - 从模型中的 API 调用返回 JSON 对象作为字典以在视图控制器中使用