Swift 无法使用枚举初始化程序访问部分 JSON 响应
Posted
技术标签:
【中文标题】Swift 无法使用枚举初始化程序访问部分 JSON 响应【英文标题】:Swift can't access part of JSON response with enum initializer 【发布时间】:2019-03-16 19:41:16 【问题描述】:我无法访问 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
]
]
接近 如您所见,源可以有多个类别。单个类别将有一个“名称”、“描述”并且可能有“子级”。孩子会有一个“名字”、“描述”,也可能有“孩子”。这可能会无穷无尽。如果没有子节点,则 SJON 语句为“假”
我使用网站:https://app.quicktype.io 来生成一个垃圾代码来解析 JSON。我修改了结果,因为网站不知道孩子们可以去无休止:
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!)
这部分工作正常。我可以访问“新生”,但无法访问他的孩子。 我搜索了很长时间,以寻找我尝试了很多的答案。在这里分享给大家。我期望获得的是:
if let temp = productCategories.responce?.categories?["\(indexPath.item)"]?.nl?.children!
let x = temp(from: Decoder)
但这会给我一个错误: "不能调用非函数类型'EnChildren'的值"
还有类似的代码:
let temp1 = productCategories.responce?.categories?["\(indexPath.item)"]?.nl?.children
不会带我去任何地方。
那么,有什么想法吗?谢谢。
【问题讨论】:
【参考方案1】:首先:如果您负责服务器端,请为叶子孩子发送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
【讨论】:
以上是关于Swift 无法使用枚举初始化程序访问部分 JSON 响应的主要内容,如果未能解决你的问题,请参考以下文章
控制台应用程序无法以域管理员身份读取基于访问的枚举的完整目录列表