Swift 无法使用枚举初始值设定项访问部分 JSON 响应
Swift can't access part of JSON response with enum initializer
我无法访问 JSON 响应的一部分。
(部分)来源:
{
"time":1552726518,
"result":"success",
"errors":null,
"responce":{
"categories":{
"1":{
"nl":{
"name":"New born",
"description":"TEST",
"children":[
{
"name":"Unisex",
"description":"TESTe",
"children":[
{
"name":"Pants",
"description":"TEST",
"children":false
}
]
}
]
}
}
}
}
}
方法
如您所见,源可以有多个类别。单个类别将具有 'name'、'description',并且可能具有 'children'。 Children 将有 'name'、'description',也可能有 'children'。这可能会没完没了。如果没有 children SJON 语句是 'false'
我使用网站:https://app.quicktype.io 生成一堆代码来解析 JSON。我修改了结果,因为网站不知道children可以无穷无尽:
struct ProductCategories: Codable {
let time: Int?
let result: String?
let errors: [String]?
let responce: ProductCategoriesResponce?
init(time: Int? = nil, result: String? = nil, errors: [String]? = nil, responce: ProductCategoriesResponce? = nil) {
self.time = time
self.result = result
self.errors = errors
self.responce = responce
}
}
struct ProductCategoriesResponce: Codable {
let categories: [String: Category]?
}
struct Category: Codable {
let nl, en: Children?
}
struct Children: Codable {
let name, description: String?
let children: EnChildren?
}
enum EnChildren: Codable {
case bool(Bool)
case childArray([Children])
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(Bool.self) {
self = .bool(x)
return
}
if let x = try? container.decode([Children].self) {
self = .childArray(x)
return
}
throw DecodingError.typeMismatch(EnChildren.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for EnChildren"))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .bool(let x):
try container.encode(x)
case .childArray(let x):
try container.encode(x)
}
}
}
我可以解码数据:
productCategories = try JSONDecoder().decode(ProductCategories.self, from: jsonData!)
这部分工作正常。我可以访问 "New Born",但无法访问他的 children。
我搜索了很长时间我尝试了这么多的答案。在这里分享很多。我希望获得的访问权限是:
if let temp = productCategories.responce?.categories?["\(indexPath.item)"]?.nl?.children! {
let x = temp(from: Decoder)
但这会给我一个错误:
"Cannot call value of non-function type 'EnChildren'"
还有这样的代码:
let temp1 = productCategories.responce?.categories?["\(indexPath.item)"]?.nl?.children
我哪儿也去不了。
那么,有什么想法吗?谢谢。
首先:如果你负责服务器端,为叶子节点发送null
或者省略密钥而不是发送false
。它使解码过程变得更加容易。
app.quicktype.io 是一个很好的资源,但我不同意它的建议。
我的解决方案使用带有自定义初始化程序的常规结构 Children
。这个结构可以递归使用。
密钥children
被有条件地解码。首先解码 [Children]
,失败时解码 Bool
并将 children
设置为 nil
或移交错误。
并且我尽可能多地将结构成员声明为非可选的
struct Response: Decodable {
let time: Date
let result: String
let errors: [String]?
let responce: ProductCategories
}
struct ProductCategories: Decodable {
let categories: [String: Category]
}
struct Category: Decodable {
let nl: Children
}
struct Children: Decodable {
let name, description: String
let children : [Children]?
private enum CodingKeys : String, CodingKey { case name, description, children }
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
description = try container.decode(String.self, forKey: .description)
do {
children = try container.decode([Children].self, forKey: .children)
} catch DecodingError.typeMismatch {
_ = try container.decode(Bool.self, forKey: .children)
children = nil
}
}
}
在根对象中,如果指定适当的日期解码策略,则密钥 time
可以解码为 Date
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let result = try decoder.decode(Response.self, from: jsonData!)
并且您可以使用
访问例如名称 Unisex
result.responce.categories["1"]?.nl.children?[0].name
我无法访问 JSON 响应的一部分。
(部分)来源:
{
"time":1552726518,
"result":"success",
"errors":null,
"responce":{
"categories":{
"1":{
"nl":{
"name":"New born",
"description":"TEST",
"children":[
{
"name":"Unisex",
"description":"TESTe",
"children":[
{
"name":"Pants",
"description":"TEST",
"children":false
}
]
}
]
}
}
}
}
}
方法 如您所见,源可以有多个类别。单个类别将具有 'name'、'description',并且可能具有 'children'。 Children 将有 'name'、'description',也可能有 'children'。这可能会没完没了。如果没有 children SJON 语句是 'false'
我使用网站:https://app.quicktype.io 生成一堆代码来解析 JSON。我修改了结果,因为网站不知道children可以无穷无尽:
struct ProductCategories: Codable {
let time: Int?
let result: String?
let errors: [String]?
let responce: ProductCategoriesResponce?
init(time: Int? = nil, result: String? = nil, errors: [String]? = nil, responce: ProductCategoriesResponce? = nil) {
self.time = time
self.result = result
self.errors = errors
self.responce = responce
}
}
struct ProductCategoriesResponce: Codable {
let categories: [String: Category]?
}
struct Category: Codable {
let nl, en: Children?
}
struct Children: Codable {
let name, description: String?
let children: EnChildren?
}
enum EnChildren: Codable {
case bool(Bool)
case childArray([Children])
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(Bool.self) {
self = .bool(x)
return
}
if let x = try? container.decode([Children].self) {
self = .childArray(x)
return
}
throw DecodingError.typeMismatch(EnChildren.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for EnChildren"))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .bool(let x):
try container.encode(x)
case .childArray(let x):
try container.encode(x)
}
}
}
我可以解码数据:
productCategories = try JSONDecoder().decode(ProductCategories.self, from: jsonData!)
这部分工作正常。我可以访问 "New Born",但无法访问他的 children。 我搜索了很长时间我尝试了这么多的答案。在这里分享很多。我希望获得的访问权限是:
if let temp = productCategories.responce?.categories?["\(indexPath.item)"]?.nl?.children! {
let x = temp(from: Decoder)
但这会给我一个错误: "Cannot call value of non-function type 'EnChildren'"
还有这样的代码:
let temp1 = productCategories.responce?.categories?["\(indexPath.item)"]?.nl?.children
我哪儿也去不了。
那么,有什么想法吗?谢谢。
首先:如果你负责服务器端,为叶子节点发送null
或者省略密钥而不是发送false
。它使解码过程变得更加容易。
app.quicktype.io 是一个很好的资源,但我不同意它的建议。
我的解决方案使用带有自定义初始化程序的常规结构 Children
。这个结构可以递归使用。
密钥children
被有条件地解码。首先解码 [Children]
,失败时解码 Bool
并将 children
设置为 nil
或移交错误。
并且我尽可能多地将结构成员声明为非可选的
struct Response: Decodable {
let time: Date
let result: String
let errors: [String]?
let responce: ProductCategories
}
struct ProductCategories: Decodable {
let categories: [String: Category]
}
struct Category: Decodable {
let nl: Children
}
struct Children: Decodable {
let name, description: String
let children : [Children]?
private enum CodingKeys : String, CodingKey { case name, description, children }
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
description = try container.decode(String.self, forKey: .description)
do {
children = try container.decode([Children].self, forKey: .children)
} catch DecodingError.typeMismatch {
_ = try container.decode(Bool.self, forKey: .children)
children = nil
}
}
}
在根对象中,如果指定适当的日期解码策略,则密钥 time
可以解码为 Date
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let result = try decoder.decode(Response.self, from: jsonData!)
并且您可以使用
访问例如名称Unisex
result.responce.categories["1"]?.nl.children?[0].name