从 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 一起使用吗?