[英]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解码为List
和EmployeeUser
对象。 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! 这个电话默默地失败了,您根本不知道问题出在哪里!
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.