快速解码 JSON 数组或字典错误
Posted
技术标签:
【中文标题】快速解码 JSON 数组或字典错误【英文标题】:decoding JSON array or dictionary error swift 【发布时间】:2018-05-04 21:26:47 【问题描述】:这是我第一次尝试 Codable/Decodable,我想解码 JSON。我正在尝试访问事件数组中的“名称”和“描述”键。下面是 JSON 的 sn-p - 我在我的代码中遇到了这个错误
“本应解码字典,但找到了一个数组。”
"pagination":
"page_number": 1,
"page_size": 50,
"continuation": "eyJwYWdlIjogMn0",
"has_more_items": true
,
"events": [
"name":
"text": "Genesis Part 4",
"html": "Genesis Part 4"
,
"description":
"text": "Wednesday, June 6-June 27, 2018\n12:00-2:15 PM, Eastern Time\n\u00a0\nCOED\n\u00a0\nBible Study Leader:\u00a0Nicki Cornett\n\u00a0\nContact:NickiCornett@gmail.com\n\u00a0\nGenesis Part 4 -\u00a0Wrestling with God - A Study on Isaac, Jacob, and Esau- Precept Workbook (NASB)\n\u00a0\nGod renews His covenant promise with Abraham through Isaac and Jacob.
这是我进行解码的方式 - (注意 - “描述”还没有出现,因为我在处理事件数组以访问名称和描述时遇到问题
struct Eventbrite: Decodable
private enum CodingKeys : String, CodingKey case events = "events", name = "name"
let events: [String:[String]]
let name: [String:[String]]
URLSession.shared.dataTask(with: url) (data, response, error) in
guard let data = data else return
do
let eventbriteData = try JSONDecoder().decode(Eventbrite.self, from: data)
print(eventbriteData.name)
【问题讨论】:
【参考方案1】:name
显然不在pagination
和events
的范围内(注意),它是一个常规的
[String:String]
字典,可以解码为另一个结构。
解码这个(因为description
不完整,我把它省略了),你不需要CodingKeys
:
struct Eventbrite: Decodable
let events: [Event]
struct Event: Decodable
let name: Name
// let description: [String:String]
struct Name : Decodable
let text, html : String
【讨论】:
感谢您的回复。您帮助我了解了它的结构以及如何正确解码。一个简单的菜鸟错误,现在更清楚了。谢谢!【参考方案2】:Right so Decodable 实际上非常聪明,因为您真的不需要编写任何代码来自己进行解码。您只需要确保匹配 JSON 结构(并为任何嵌套对象制作也符合 Decodable 的结构)。换句话说,不要将变量作为字典,而是让它们成为自己的可解码结构。
例如:
struct EventBrite: Decodable
let pagination: Pagination
let events: [Event]
struct Pagination: Decodable
let page_number: Int
let page_size: Int
let continuation: String
let has_more_items: Bool
struct Event: Decodable
let name: EventName
let description: EventDescription
struct EventName: Decodable
let name: String
let html: String
等等……
这里重要的一点是,如果不能保证返回键或属性(例如,假设 EventName
并不总是具有从服务器返回的 html 值,您可以轻松地标记该值作为可选。所以类似于:
struct EventName: Decodable
let name: String
let html: String?
另一方面,您实际上弄乱了字典类型声明。您会注意到event
实际上是[String: [String: String]]
类型,因为键是字符串,而值似乎总是字典。名字是[String: String]
。这不是您在原始问题中所记录的内容。
当值可能与分页不同时,您需要执行[String: Any]
之类的操作,因此请小心。
但是我认为我建议的方法比将属性作为字典更好。对于一个你不必担心声明它是字典的类型(你在上面犯了一些小错误)。但更重要的是,当每个字典都成为自己明确定义的结构时,您不必担心记住或查找键。点语法/自动完成会自动告诉你可以有什么! (当你的值是 Any
或 AnyObject
时,不要强制转换!)
也绝对使用结构来完成所有这些工作,因为我曾经对性能进行基准测试,并测量了结构效率,其效率是类的数百万倍。仅供参考。
【讨论】:
感谢您的解释。您进一步帮助我了解了这个概念! 嘿,回头看看这条评论,我现在真的有点困惑,你的最终建议是什么?您能否澄清所有编辑的含义。谢谢 对,所以我的建议是,代替在任何地方使用字典作为属性,创建一个也符合 Decodable 的新结构。所以不必做event["name"]
你可以做event.name
。在我看来,它更容易使用,只要属性匹配,Decodable 的魔力就会始终正确解析。另一个好处是,您实际上稍微搞砸了字典的类型,因此您不必担心。例如。正如我所说的名字不是[String:[String]]
它的[String: String]
又名。只要属性不是直接的原始类型值(String
、Bool
、Int
等),就会创建一个嵌套更深的新结构。而不是将其保存为字典。
非常感谢您的澄清。这完全有道理,我能够重组并成功运行它以上是关于快速解码 JSON 数组或字典错误的主要内容,如果未能解决你的问题,请参考以下文章
错误:“应解码 Dictionary<String, Any>,但找到了一个数组。” ——但我还没有定义字典? [复制]
解码错误:typeMismatch“预期解码 Array<Any> 但找到了字典。”
JSON解码致命错误:不能使用stdClass类型的对象作为数组