【问题标题】:swift4 encoding decoding for model class of nested json parsing嵌套json解析模型类的swift4编码解码
【发布时间】:2018-03-20 11:43:13
【问题描述】:

我有一个基于嵌套 json 响应创建的 swift 模型类,如下所示

struct RootClass : Codable {
    let details : String?
    let itemCount : Int?
    let list : [List]?

    enum CodingKeys: String, CodingKey {
        case details = "Details"
        case itemCount = "ItemCount"
        case list = "List"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        details = try values.decodeIfPresent(String.self, forKey: .details)
        itemCount = try values.decodeIfPresent(Int.self, forKey: .itemCount)
        list = try values.decodeIfPresent([List].self, forKey: .list)
    }
}
struct List : Codable {

    let companyID : Int?
    let employeeCount : Int?
    let employeeUser : EmployeeUser?

    enum CodingKeys: String, CodingKey {
        case companyID = "CompanyID"
        case employeeCount = "EmployeeCount"
        case employeeUser = "EmployeeUser"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        companyID = try values.decodeIfPresent(Int.self, forKey: .companyID)
        employeeCount = try values.decodeIfPresent(Int.self, forKey: .employeeCount)
        employeeUser = try EmployeeUser(from: decoder)
    }
}
struct EmployeeUser : Codable {
    let mobileNumber : String?
    let name : String?

    enum CodingKeys: String, CodingKey {
        case mobileNumber = "MobileNumber"
        case name = "Name"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        mobileNumber = try values.decodeIfPresent(String.self, forKey: .mobileNumber)
        name = try values.decodeIfPresent(String.self, forKey: .name)
    }

}

我的 json 响应是

{
    "Details": null,
    "List": [
        {
            "CompanyID": 140,
            "EmployeeUser": {
                "Name": " raghu2",
                "MobileNumber": "8718718710"
            },
            "EmployeeCount": 0
        },
        {
            "CompanyID": 140,
            "EmployeeUser": {
                "Name": "new emp reg",
                "MobileNumber": "1"
            },
            "EmployeeCount": 0
        }
    ],
    "ItemCount": 0
}

我正在尝试像

一样解析它
guard let data = data else { return }
        do {
            let decoder = JSONDecoder()
            let gitData = try decoder.decode(RootClass.self, from: data)
            print(gitData.itemCount ?? "")
            print(gitData.list![0].employeeUser?.mobileNumber ?? "")
        }
        catch let err {
            print("Err", err)
        }

我能够获取根类和列表的值,但我在员工用户部分下得到 nil 值。

【问题讨论】:

    标签: json encoding model swift4 decoding


    【解决方案1】:

    你的代码有几个问题:

    • 您的所有密钥都是可选的。供应商 API 将告诉您哪些密钥始终存在,哪些是可选的。跟着那个。

    • decodeIfPresent 如果无法解码密钥,将静默失败。在调试您的应用时,您希望事情一败涂地,以便在投入生产之前修复错误。

    • 您编写的代码比需要的多。不需要所有这些init(from decoder: ) 函数。一个确实导致了您的问题。

    你的问题是由这行引起的:

    struct List : Codable {
        init(from decoder: Decoder) throws {
            ...
            employeeUser = try EmployeeUser(from: decoder)
        }
    }
    

    您要求 Swift 将相同的 JSON 解码为 ListEmployeeUser 对象。显然,这是无效的。但是当你在 RootClass 中解码list 时,你调用了decodeIfPresent

    // In Rootclass
    list = try values.decodeIfPresent([List].self, forKey: .list)
    

    这个调用无声无息地失败了,你永远不知道问题出在哪里!


    解决方案

    将您初始化 employeeUser 的方式更改为:

    employeeUser = try values.decodeIfPresent(EmployeeUser.self, forKey: .employeeUser)
    

    但最优雅的解决方案是删除所有init(from decoder: )。编译器会为你合成它们。

    最后,修复这些选项!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多