从 api SwiftUI 解码 JSON 文件

Posted

技术标签:

【中文标题】从 api SwiftUI 解码 JSON 文件【英文标题】:Decode JSON file from api SwiftUI 【发布时间】:2020-03-16 08:27:40 【问题描述】:

我正在尝试从 URL 解码一些 JSON 数据并将其显示在列表中。我尝试了不同的方法,但没有一种方法有效(有时它会返回未知错误或根本不显示数据) 这应该是表示 JSON 格式的结构

import SwiftUI

struct Country : Decodable 
    var thailand : [Case]


struct Case : Decodable  
    var date : String
    var confirmed : Int
    var deaths : Int
    var recovered : Int

JSON 的一小部分(但都一样):



  "Thailand": [
    
      "date": "2020-1-22",
      "confirmed": 2,
      "deaths": 0,
      "recovered": 0
    ,
    
      "date": "2020-1-23",
      "confirmed": 3,
      "deaths": 0,
      "recovered": 0
    ,
    
      "date": "2020-1-24",
      "confirmed": 5,
      "deaths": 0,
      "recovered": 0
    ,
    
      "date": "2020-1-25",
      "confirmed": 7,
      "deaths": 0,
      "recovered": 0
    ,
    
      "date": "2020-1-26",
      "confirmed": 8,
      "deaths": 0,
      "recovered": 2
    ,
    
      "date": "2020-1-27",
      "confirmed": 8,
      "deaths": 0,
      "recovered": 2
    ,
    
      "date": "2020-1-28",
      "confirmed": 14,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-1-29",
      "confirmed": 14,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-1-30",
      "confirmed": 14,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-1-31",
      "confirmed": 19,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-2-1",
      "confirmed": 19,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-2-2",
      "confirmed": 19,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-2-3",
      "confirmed": 19,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-2-4",
      "confirmed": 25,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-2-5",
      "confirmed": 25,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-2-6",
      "confirmed": 25,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-2-7",
      "confirmed": 25,
      "deaths": 0,
      "recovered": 5
    ,
    
      "date": "2020-2-8",
      "confirmed": 32,
      "deaths": 0,
      "recovered": 10
    ,
    
      "date": "2020-2-9",
      "confirmed": 32,
      "deaths": 0,
      "recovered": 10
    ,
    
      "date": "2020-2-10",
      "confirmed": 32,
      "deaths": 0,
      "recovered": 10
    ,
    
      "date": "2020-2-11",
      "confirmed": 33,
      "deaths": 0,
      "recovered": 10
    ,
    
      "date": "2020-2-12",
      "confirmed": 33,
      "deaths": 0,
      "recovered": 10
    ,
    
      "date": "2020-2-13",
      "confirmed": 33,
      "deaths": 0,
      "recovered": 12
    ,
    
      "date": "2020-2-14",
      "confirmed": 33,
      "deaths": 0,
      "recovered": 12
    ,
    
      "date": "2020-2-15",
      "confirmed": 33,
      "deaths": 0,
      "recovered": 12
    ,
    
      "date": "2020-2-16",
      "confirmed": 34,
      "deaths": 0,
      "recovered": 14
    ,
    
      "date": "2020-2-17",
      "confirmed": 35,
      "deaths": 0,
      "recovered": 15
    ,
    
      "date": "2020-2-18",
      "confirmed": 35,
      "deaths": 0,
      "recovered": 15
    ,
    
      "date": "2020-2-19",
      "confirmed": 35,
      "deaths": 0,
      "recovered": 15
    ,
    
      "date": "2020-2-20",
      "confirmed": 35,
      "deaths": 0,
      "recovered": 15
    ,
    
      "date": "2020-2-21",
      "confirmed": 35,
      "deaths": 0,
      "recovered": 17
    ,
    
      "date": "2020-2-22",
      "confirmed": 35,
      "deaths": 0,
      "recovered": 17
    ,
    
      "date": "2020-2-23",
      "confirmed": 35,
      "deaths": 0,
      "recovered": 21
    ,
    
      "date": "2020-2-24",
      "confirmed": 35,
      "deaths": 0,
      "recovered": 21
    ,
    
      "date": "2020-2-25",
      "confirmed": 37,
      "deaths": 0,
      "recovered": 22
    ,
    
      "date": "2020-2-26",
      "confirmed": 40,
      "deaths": 0,
      "recovered": 22
    ,
    
      "date": "2020-2-27",
      "confirmed": 40,
      "deaths": 0,
      "recovered": 22
    ,
    
      "date": "2020-2-28",
      "confirmed": 41,
      "deaths": 0,
      "recovered": 28
    ,
    
      "date": "2020-2-29",
      "confirmed": 42,
      "deaths": 0,
      "recovered": 28
    ,
    
      "date": "2020-3-1",
      "confirmed": 42,
      "deaths": 1,
      "recovered": 28
    ,
    
      "date": "2020-3-2",
      "confirmed": 43,
      "deaths": 1,
      "recovered": 31
    ,
    
      "date": "2020-3-3",
      "confirmed": 43,
      "deaths": 1,
      "recovered": 31
    ,
    
      "date": "2020-3-4",
      "confirmed": 43,
      "deaths": 1,
      "recovered": 31
    ,
    
      "date": "2020-3-5",
      "confirmed": 47,
      "deaths": 1,
      "recovered": 31
    ,
    
      "date": "2020-3-6",
      "confirmed": 48,
      "deaths": 1,
      "recovered": 31
    ,
    
      "date": "2020-3-7",
      "confirmed": 50,
      "deaths": 1,
      "recovered": 31
    ,
    
      "date": "2020-3-8",
      "confirmed": 50,
      "deaths": 1,
      "recovered": 31
    ,
    
      "date": "2020-3-9",
      "confirmed": 50,
      "deaths": 1,
      "recovered": 31
    ,
    
      "date": "2020-3-10",
      "confirmed": 53,
      "deaths": 1,
      "recovered": 33
    ,
    
      "date": "2020-3-11",
      "confirmed": 59,
      "deaths": 1,
      "recovered": 34
    ,
    
      "date": "2020-3-12",
      "confirmed": 70,
      "deaths": 1,
      "recovered": 34
    ,
    
      "date": "2020-3-13",
      "confirmed": 75,
      "deaths": 1,
      "recovered": 35
    ,
    
      "date": "2020-3-14",
      "confirmed": 82,
      "deaths": 1,
      "recovered": 35
    ,
    
      "date": "2020-3-15",
      "confirmed": 114,
      "deaths": 1,
      "recovered": 35
    
  ],
  "Japan": [
    
      "date": "2020-1-22",
      "confirmed": 2,
      "deaths": 0,
      "recovered": 0
    ,
    
      "date": "2020-1-23",
      "confirmed": 1,
      "deaths": 0,
      "recovered": 0
    ,
    
      "date": "2020-1-24",
      "confirmed": 2,
      "deaths": 0,
      "recovered": 0
    ,
    
      "date": "2020-1-25",
      "confirmed": 2,
      "deaths": 0,
      "recovered": 0
    ,
    
      "date": "2020-1-26",
      "confirmed": 4,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-1-27",
      "confirmed": 4,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-1-28",
      "confirmed": 7,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-1-29",
      "confirmed": 7,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-1-30",
      "confirmed": 11,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-1-31",
      "confirmed": 15,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-1",
      "confirmed": 20,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-2",
      "confirmed": 20,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-3",
      "confirmed": 20,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-4",
      "confirmed": 22,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-5",
      "confirmed": 22,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-6",
      "confirmed": 45,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-7",
      "confirmed": 25,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-8",
      "confirmed": 25,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-9",
      "confirmed": 26,
      "deaths": 0,
      "recovered": 1
    ,
    
      "date": "2020-2-10",
      "confirmed": 26,
      "deaths": 0,
      "recovered": 4
    ,
    
      "date": "2020-2-11",
      "confirmed": 26,
      "deaths": 0,
      "recovered": 9
    ,
    
      "date": "2020-2-12",
      "confirmed": 28,
      "deaths": 0,
      "recovered": 9
    ,
    
      "date": "2020-2-13",
      "confirmed": 28,
      "deaths": 1,
      "recovered": 9
    ,
    
      "date": "2020-2-14",
      "confirmed": 29,
      "deaths": 1,
      "recovered": 9
    ,
    
      "date": "2020-2-15",
      "confirmed": 43,
      "deaths": 1,
      "recovered": 12
    ,
    
      "date": "2020-2-16",
      "confirmed": 59,
      "deaths": 1,
      "recovered": 12
    ,
    
      "date": "2020-2-17",
      "confirmed": 66,
      "deaths": 1,
      "recovered": 12
    ,
    
      "date": "2020-2-18",
      "confirmed": 74,
      "deaths": 1,
      "recovered": 13
    ,
    
      "date": "2020-2-19",
      "confirmed": 84,
      "deaths": 1,
      "recovered": 18
    ,
    
      "date": "2020-2-20",
      "confirmed": 94,
      "deaths": 1,
      "recovered": 18
    ,
    
      "date": "2020-2-21",
      "confirmed": 105,
      "deaths": 1,
      "recovered": 22
    ,
    
      "date": "2020-2-22",
      "confirmed": 122,
      "deaths": 1,
      "recovered": 22
    ,
    
      "date": "2020-2-23",
      "confirmed": 147,
      "deaths": 1,
      "recovered": 22
    ,
    
      "date": "2020-2-24",
      "confirmed": 159,
      "deaths": 1,
      "recovered": 22
    ,
    
      "date": "2020-2-25",
      "confirmed": 170,
      "deaths": 1,
      "recovered": 22
    ,
    
      "date": "2020-2-26",
      "confirmed": 189,
      "deaths": 2,
      "recovered": 22
    ,
    
      "date": "2020-2-27",
      "confirmed": 214,
      "deaths": 4,
      "recovered": 22
    ,
    
      "date": "2020-2-28",
      "confirmed": 228,
      "deaths": 4,
      "recovered": 22
    ,
    
      "date": "2020-2-29",
      "confirmed": 241,
      "deaths": 5,
      "recovered": 32
    ,
    
      "date": "2020-3-1",
      "confirmed": 256,
      "deaths": 6,
      "recovered": 32
    ,
    
      "date": "2020-3-2",
      "confirmed": 274,
      "deaths": 6,
      "recovered": 32
    ,
    
      "date": "2020-3-3",
      "confirmed": 293,
      "deaths": 6,
      "recovered": 43
    ,
    
      "date": "2020-3-4",
      "confirmed": 331,
      "deaths": 6,
      "recovered": 43
    ,
    
      "date": "2020-3-5",
      "confirmed": 360,
      "deaths": 6,
      "recovered": 43
    ,
    
      "date": "2020-3-6",
      "confirmed": 420,
      "deaths": 6,
      "recovered": 46
    ,
    
      "date": "2020-3-7",
      "confirmed": 461,
      "deaths": 6,
      "recovered": 76
    ,
    
      "date": "2020-3-8",
      "confirmed": 502,
      "deaths": 6,
      "recovered": 76
    ,
    
      "date": "2020-3-9",
      "confirmed": 511,
      "deaths": 10,
      "recovered": 76
    ,
    
      "date": "2020-3-10",
      "confirmed": 581,
      "deaths": 10,
      "recovered": 101
    ,
    
      "date": "2020-3-11",
      "confirmed": 639,
      "deaths": 15,
      "recovered": 118
    ,
    
      "date": "2020-3-12",
      "confirmed": 639,
      "deaths": 16,
      "recovered": 118
    ,
    
      "date": "2020-3-13",
      "confirmed": 701,
      "deaths": 19,
      "recovered": 118
    ,
    
      "date": "2020-3-14",
      "confirmed": 773,
      "deaths": 22,
      "recovered": 118
    ,
    
      "date": "2020-3-15",
      "confirmed": 839,
      "deaths": 22,
      "recovered": 118
    
  ]

这里我尝试解码 JSON 并将其插入动态列表中


import SwiftUI

struct ContentView: View 

    @State private var cases = [Case]()

    var body: some View 
        List(cases , id: \.date)  i in
            VStack
                Text(i.date)
                Text("\(i.deaths)")
                Text("\(i.confirmed)")
                Text("\(i.recovered)")

            .onAppear(perform: self.loadData)

    


    func loadData() 
        guard let url = URL(string: "https://pomber.github.io/covid19/timeseries.json") else 
            print("Invalid URL")
            return
        
        let request = URLRequest(url: url)
        URLSession.shared.dataTask(with: request)  data, response, error in

            if let data = data 
                if let decodedResponse = try? JSONDecoder().decode(Country.self, from: data) 

                    DispatchQueue.main.async 
                        print(decodedResponse)
                        self.cases = decodedResponse.thailand
                    
                    return
                
            

            // if we're still here it means there was a problem
            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")

        .resume()

    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    


【问题讨论】:

避免使用try?,使用do/catch!如果有错误,您将忽略错误。例如Thailand vs thailand(第一个字母大写)。 对于多个国家/地区删除Country并解码[String:[Case]] 我试过了,还是不行。它没有给我任何错误,但它显示一个空列表。 它没有给我任何错误。毫不奇怪,您忽略了所有可能的错误。 对某些解决方案有任何参考吗?我对 swift 很陌生,所以我还在学习 【参考方案1】:

为了解码您的回复,您可以使用这种方式:


typealias Country = [String: [Case]]


struct Case : Decodable  
    var date : String
    var confirmed : Int
    var deaths : Int
    var recovered : Int


然后解码你的数据

decodedResponse = try? JSONDecoder().decode(Country.self, from: data)

decodedResponse 为您提供包含所有国家/地区的字典。

for循环在国家/地区,您可以为一个国家/地区设置和获取信息


for country in decodedResponse.keys 
     let cases = decodedResponse[country]

【讨论】:

我应该把国家的钥匙放在哪里?非常感谢 decodedResponse.keys 包含国家名称。您可以在其中搜索您需要的目标 我不明白。对不起 如果我理解正确,如果您需要某个国家的案例,例如日本,您可以这样做:let countryName = "Japan" if decodedResponse.keys.contains(countryName) self.cases = decodedResponse[countryName] ?? []

以上是关于从 api SwiftUI 解码 JSON 文件的主要内容,如果未能解决你的问题,请参考以下文章

通过 PHP 将来自 MySQL 的 JSON 解码为 SwiftUI 中的复杂结构

使用 Codable 解码 JSON,然后填充我的 SwiftUI

从公共 API 获取 JSON 以在 SwiftUI 的列表视图中呈现

SwiftUI:你可以将 AppStorage 与解码的 json 一起使用吗?

SwiftUI 如何从响应 JSON API 中分离单个数据

SwiftUI - 类型“服务”不符合协议“可解码”