JSONDecoder 解析不连贯

Posted

技术标签:

【中文标题】JSONDecoder 解析不连贯【英文标题】:JSONDecoder parsing incoherence 【发布时间】:2021-07-19 21:01:07 【问题描述】:

我在解码 JSON 文件时遇到了问题。

文件结构如下:

"grocery":
    [
         "vegetables":
            "quantity":"some",
            "compostable":true,
            "stockageSite":"string",
            "package":"bag"
            ,

        "meats":
            "quantity":"string",
            "compostable":true,
            "stockageSite":"string",
            "package":"box"
            ,

        "site":"string",
        "active":true,
        "name":"string"
        
    ]


我有以下结构

struct Goods: Codable 
    
    var quantity: String
    var compostable: Bool
    var stockageSite: String
    var package: String


struct Details: Codable 
    
    var vegetables: Goods
    var meats: Goods
    var site: String
    var active: Bool
    var name: String


struct Grocery: Codable 

    var grocery: [Details]

解码(do-catch with

 URLSession.shared.dataTask(with: request)data, response, error in
            if let error = error 
                print("Error took place: \(error)")
                return
            
            if let response = response as? HTTPURLResponse 
                if response.statusCode != 200
                    print("Response HTTP Status code: \(response.statusCode)")
                
            
            if let data = data
              
            let decoder = JSONDecoder()
 do 
            let jsonParse: Grocery =  try decoder.decode(Grocery.self, from: data)
            print("parsed \(jsonParse)")

catch let jsonError as NSError
                    
                    print("Failed \(jsonError)")
                

) 解析得非常好,只要我从商品中删除“数量”或“库存站点”或“包装”(-> 即具有字符串值的那些,就像超过 2 个字符串项一样)在那里不起作用)。否则,没有解析并且代码执行在那里停止。没有抛出错误(游乐场除外:

error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

字符串类型很好,没有错别字。 “可堆肥”(bool)是公认的。

(如果我将字符串元素添加到“详细信息”并相应地更改我的 json,也会发生同样的事情。)

这里是正确解析后打印的结果(3个字符串元素中的哪个被删除,所以“包”可以正确解析):

解析的杂货(杂货:[__lldb_expr_5.Details(蔬菜:__lldb_expr_5.Goods(数量:“一些”,可堆肥:true,stockageSite:“字符串”),肉类:__lldb_expr_5.Goods(数量:“字符串”,可堆肥: true, stockageSite: "string"), site: "string", active: true, name: "string")])

并且(有时!但为什么?!)打印的错误消息:

失败的 Swift.DecodingError.valueNotFound(__lldb_expr_7.Details, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "grocery", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "预期的详细信息,但发现为空。",底层错误:nil))

就像从未找到第三个字符串元素一样。你能知道发生了什么吗?

【问题讨论】:

您创建错误变量并打印它吗? do // ... catch (let error) print(error) "解析非常好,没有抛出错误" 怎么样?一个叫“数据”的人是从哪里来的? 将它们声明为可选 为上面的 cmets 编辑了我的问题。可选不会改变任何东西。将数据打印为字符串显示值存在。 @NightCoder 显示您的实际 JSON。如果您发布没有任何意义的 JSON,没有人能够提供帮助。至少添加你说你正在捕捉的错误。 【参考方案1】:

问题需要更多信息,但我猜这些对象中的键有时会丢失,所以这里是您如何处理它,只需使用 init(from decoder: Decoder) 并使用 decodeIfPresent 为丢失的键提供默认值更改您的 @ 987654323@ 结构到这个

    struct Goods: Codable 
    var quantity: String
    var compostable: String
    var stockageSite: String
    
   private enum CodingKeys: String, CodingKey 
        case quantity
        case compostable
        case stockageSite
   
    init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        self.quantity = try container.decodeIfPresent(String.self, forKey: .quantity) ?? "Empty"
        self.compostable = try container.decodeIfPresent(String.self, forKey: .compostable) ?? "Empty"
        self.stockageSite = try container.decodeIfPresent(String.self, forKey: .stockageSite) ?? "Empty"

        

【讨论】:

谢谢!但是 JSON 是本地文件,没有丢失键 你试过了吗?答案 并使这两个键可选 我做了......不幸的是没有变化:(

以上是关于JSONDecoder 解析不连贯的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 中解析没有 JSONdecoder 的 JSON 对象? [复制]

为啥 JsonDecoder 在尝试解析邮递员网址但处理其他网址时出现错误?

告诉 numberOfRowsInSection 在使用 MVVM 架构在闭包中使用 JSONDecoder 解析 JSON 后它需要多少行

如何使用 JSONDecoder 根据订单键获取排序数据?

JSONDecoder 找不到存在的密钥

Swift JSONDecoder 默认替换所有缺失的键?