【问题标题】:How to decode nested json on to a custom class with array in Swift?如何在 Swift 中将嵌套的 json 解码为带有数组的自定义类?
【发布时间】:2020-03-12 09:34:00
【问题描述】:

我在尝试将嵌套的 json 响应解析为自定义可解码响应类时收到 nil

自定义响应类:

class User: Decodable, Encodable {

    var name: String?
    var email: String?
    var token: String?

    enum CodingKeys: String, CodingKey {
        case name
        case email
        case token
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try? container.decode(String.self, forKey: .name)
        self.email = try? container.decode(String.self, forKey: .email)
        self.token = try? container.decode(String.self, forKey: .token)
    }
}

class ResponseData: Decodable {

    let body: [User]?

    enum CodingKeys: String, CodingKey {
        case users
        case body
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let response = try container.nestedContainer(keyedBy:CodingKeys.self, forKey: .body)
        self.body = try response.decode([User].self, forKey: .users)
    }
}

class ResponseRoot: Decodable {
    let data : ResponseData?

    enum CodingKeys: String, CodingKey { case data }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.data = try? container.decode(ResponseData.self, forKey: .data)
    }
}

用于解析的 Json 响应,

{
    "status": "success",
    "errorMessage": null,
    "data": {
        "headers": {},
        "body": [
            {
                "name": "Alex",
                "email": "alex@b.c",
                "password": "1234",
                "token": "1234",
                "loginStatus": 0
            },
            {
                "name": "Einstein",
                "email": "e@b.c",
                "password": "1234",
                "token": "A valid token",
                "loginStatus": 1
            }
        ],
        "statusCode": "OK",
        "statusCodeValue": 200
    }
}

Alamofire 呼叫,

Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.queryString, headers: nil)
         .validate()
         .responseJSON { response in

            switch (response.result) {

                case .success( _):

                do {
                    let users = try JSONDecoder().decode(ResponseRoot.self, from: response.data!) // getting users = nil
                    completion((users.data?.body!)!)

                } catch let error as NSError {
                    print("Failed to load: \(error.localizedDescription)")
                    completion([])
                }

                 case .failure(let error):
                    print("Request error: \(error.localizedDescription)")
                    completion([])
             }

现在,let users = try JSONDecoder().decode(ResponseRoot.self, from: response.data!) 不会创建任何异常,但 users 为零。

【问题讨论】:

  • Statuscode 400 是服务器错误,与解码部分无关。并且永远不要打印localizedDescriptionDecodingError。你扔掉了全面的错误信息。
  • 在.failure的情况下不是HTTP请求的请求错误吗? API 调用失败,因此它不执行解码行
  • 我得到了有效的响应数据
  • @aiwiguna & @vadian,我更新了帖子。错误来自以前的日志。我为我的误会道歉。但现在我收到了nil
  • 看起来您可以删除一半的代码。 Codingkeys 并不是真正需要的,因为您的变量名称与键相同。结构内部也不需要初始化器。您所要做的就是调用 JSONDecoder.decode(ResponseRoot, from: data) 它应该可以工作。

标签: json swift nested alamofire decodable


【解决方案1】:

您制作的结构(在我看来)过于复杂。它们可能是:

class User: Codable {

    var name: String
    var email: String
    var token: String
}

class ResponseData: Codable {

    let body: [User]?
}

class ResponseRoot: Codable {
    let data : ResponseData
}

然后只需在 try catch 块内调用 JSONDecoder().decode(ResponseRoot.self, from: data)

【讨论】:

  • 哇。非常感谢。它与 let users = try JSONDecoder().decode(ResponseRoot.self, from: response.data!) 在 try 中一起使用。
  • 但是,如果我的键名和变量名不同,我的实现出了什么问题?
  • 如果您有一个名为 usrid 的 JSON 密钥,它代表用户 ID,但您希望将该密钥解码为一个名为 userID 的变量,您可以使用这样的编码密钥:enum CodingKeys: String, CodingKey { case userID = "usrid" }
  • 是的,我知道。我要问的是,为什么我以前的代码在我做得很好时却没有正确解析,尽管工作过度了。
  • 不太确定,可能是因为每个单独的结构中的初始化程序,或者所有变量都是可选的。不太清楚,抱歉。你可以把这两个东西一个一个去掉,看看什么时候开始工作?
猜你喜欢
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 2021-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多