简体   繁体   English

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

[英]swift4 encoding decoding for model class of nested json parsing

I have a model class of swift which was created based on a nested json response, it follows like below 我有一个swift的模型类,它是基于嵌套的json响应创建的,如下所示

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)
    }

}

and my json response is 我的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
}

I am trying to parse it like 我试图解析它像

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)
        }

I am able to get the values of root class and list but I am getting nil values under employee user section. 我能够获取根类和列表的值,但在雇员用户部分下却得到nil值。

Your code a few problems: 您的代码有几个问题:

  • All your keys are optional. 您所有的键都是可选的。 The vendor API will tell you what keys are always present and which one are optional. 供应商API会告诉您始终存在哪些密钥,哪些是可选的。 Follow that. 跟随那个。

  • decodeIfPresent will silently fail if it cannot decode a key. 如果无法解码密钥,则decodeIfPresent将静默失败。 When debugging your app, you want things to fail with a bang so you can fix the error before going to production. 在调试应用程序时,您希望事情以失败告终,以便可以在生产之前修复错误。

  • You wrote way more code than needed. 您编写的代码远远超出了需要。 All those init(from decoder: ) functions are not needed. 不需要所有这些init(from decoder: )函数。 One one did cause your problem. 一个确实引起您的问题。

Your problem was caused by this line: 您的问题是由以下行引起的:

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

You are asking Swift to decode to same JSON to a List and a EmployeeUser object. 您正在要求Swift将相同的JSON解码为ListEmployeeUser对象。 Obviously, that's not valid. 显然,那是无效的。 But when you decode list inside RootClass, you call decodeIfPresent : 但是,当您在RootClass内解码list时,会调用decodeIfPresent

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

This call silently failed and you never knew what the problem was! 这个电话默默地失败了,您根本不知道问题出在哪里!


Solution

Change how you initialize employeeUser to this: 将您初始化employeeUser方式更改为此:

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

But the most elegant solution is to delete all those init(from decoder: ) . 但最优雅的解决方案是删除所有那些init(from decoder: ) The compiler will synthesize them for you. 编译器将为您合成它们。

And finally, fix those optionals! 最后,修复这些可选项!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM