【问题标题】:decoding JSON array or dictionary error swift快速解码 JSON 数组或字典错误
【发布时间】: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)

【问题讨论】:

    标签: json swift decode


    【解决方案1】:

    name 显然不在paginationevents 的范围内(注意{}),它是一个常规的[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] 之类的操作,因此请小心。

    但是我认为我建议的方法比将属性作为字典更好。对于一个你不必担心声明它是字典的类型(你在上面犯了一些小错误)。但更重要的是,当每个字典都成为自己明确定义的结构时,您不必担心记住或查找键。点语法/自动完成会自动告诉你可以有什么! (当你的值是 AnyAnyObject 时,不要强制转换!)

    也绝对使用结构来完成所有这些工作,因为我曾经对性能进行基准测试,并测量了结构效率,其效率是类的数百万倍。仅供参考。

    【讨论】:

    • 感谢您的解释。您进一步帮助我了解了这个概念!
    • 嘿,回头看看这条评论,我现在真的有点困惑,你的最终建议是什么?您能否澄清所有编辑的含义。谢谢
    • 对,所以我的建议是,代替在任何地方使用字典作为属性,创建一个也符合 Decodable 的新结构。所以不必做event["name"] 你可以做event.name。在我看来,它更容易使用,只要属性匹配,Decodable 的魔力就会始终正确解析。另一个好处是,您实际上稍微搞砸了字典的类型,因此您不必担心。例如。正如我所说的名字不是[String:[String]]它的[String: String]
    • 又名。只要属性不是直接的原始类型值(StringBoolInt 等),就会创建一个嵌套更深的新结构。而不是将其保存为字典。
    • 非常感谢您的澄清。这完全有道理,我能够重组并成功运行它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-12
    相关资源
    最近更新 更多