首页 > 解决方案 > 如何将 JSONDecoder 与多种可能的数据结构一起使用

问题描述

我正在解析代表事件的 json 数据提要。在有事件发生的那一天,json 提要将是一个字典字典,看起来像这样:

{
    "19374176" : 
    {
        "event_title" : "Cool Fun Thing to Do",
        "event_description" : "Have fun and do something cool",
        "event_start_time" : "13:00:00",
        "event_end_time" : "14:00:00"
    },
    "90485761634" :
    {
        "event_title" : "Nap Time",
        "event_description" : "Lay down and go to sleep.",
        "event_start_time" : "15:00:00",
        "event_end_time" : "16:00:00"
    }
}

我已经建立了一个结构,我可以按照我目前想要的方式解码和使用这些信息,这个代码是一个更大的函数的一部分:

URLSession.shared.dataTask(with: url){(data, response, error) in
        if error != nil {
            print("session error: ", error!.localizedDescription)
        }

        guard let data = data else { return }

        do {
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            print(data)
            var eventData = try decoder.decode([String:Event].self, from: data)

            DispatchQueue.main.async{
                self.events = Array(eventData.values).sorted(by: {$0.timeStart < $1.timeStart
                })

                self.updateView()
                self.refreshControl.endRefreshing()
                self.activityIndicatorView.stopAnimating()
            }
        } catch DecodingError.typeMismatch(let type, let context){
            //No Dictionary of Events in Data
            print("key:", type, "context: ", context)
        } catch let jsonError{
            print("json error: ", jsonError)
        }
    }.resume()
}

我现在的问题是,在没有事件的日子里,json 提要是一个空数组:

[]

这会导致我处理的类型不匹配,但是如果我尝试从 catch 中调用 updateView、refreshControl 或 activityIndi​​catorView 的函数,我会收到一个错误,我无法在主线程之外调用它们。

我尝试做嵌套尝试块来分配 eventData 变量(首先查看它是否是 [String]((空数组,无事件)),然后分配给 [String:Any]((带有事件值的数组))) ,但这给了我 URLSession 的错误。

有没有更好的方法来查看 json 是空数组还是我的事件值的填充字典并更新视图?

标签: jsonswiftdecodable

解决方案


尝试在任何块之外刷新它们

do { 
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    print(data)
    var eventData = try decoder.decode([String:Event].self, from: data)
    self.events = Array(eventData.values).sorted(by: {$0.timeStart < $1.timeStart

} catch DecodingError.typeMismatch(let type, let context){
    //No Dictionary of Events in Data
    print("key:", type, "context: ", context)
} catch let jsonError{
    print("json error: ", jsonError)
}

DispatchQueue.main.async{
    self.updateView()
    self.refreshControl.endRefreshing()
    self.activityIndicatorView.stopAnimating()
}

推荐阅读