swift4编码解码嵌套json解析的模型类

时间:2018-03-20 11:43:13

标签: json encoding model swift4 decoding

我有一个基于嵌套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值。

1 个答案:

答案 0 :(得分:0)

您的代码存在一些问题:

  • 您的所有密钥都是可选的。供应商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: )。编译器会为你合成它们。

最后,修复这些选项!