如何在视图中将此本地 JSON 文件中的数组显示为 SwiftUI 列表?
How do I display an array from this local JSON file as a SwiftUI list in a view?
例如,我如何显示列表中每条记录的描述符,例如:
- 疯狂、果味
- 胖子
- 果味
(请注意,我在模型中将描述符设为可选,因为数组可能为空)
这是我的 JSON 文件代码,来自名为 flavors.json 的文件:
[
{
"id": "U45773",
"flavorGroup": "CASHEW",
"name": "NATURAL CASHEW FLAVORING",
"isBeer": true,
"isSeltzer": true,
"isNatural": true,
"descriptors": ["NUTTY", "FRUITY"],
"keywords": ["aromatic", "fattt-buttery", "brown", "nutty", "roasted", "creamy"]
},
{
"id": "U63639",
"flavorGroup": "BLACK WALNUT",
"name": "NATURAL AND ARTIFICIAL WALNUT FLAVOR",
"isBeer": true,
"isSeltzer": false,
"isNatural": true,
"descriptors": ["FATTY"],
"keywords": ["sweet", "molasses", "woody", "slight dried fruit (amber ale)"]
},
{
"id": "562811",
"flavorGroup": "APRICOT",
"name": "NATURAL AND ARTIFICIAL APRICOT FLAVOR",
"isBeer": true,
"isSeltzer": false,
"isNatural": true,
"descriptors": ["FRUITY"],
"keywords": ["juicy", "skunky", "peach", "floral", "slight green (sierra nevada pale ale)"]
}
]
这是我的模型代码:
struct Flavor: Codable, Identifiable {
enum CodingKeys: CodingKey {
case id
case flavorGroup
case name
case isBeer
case isSeltzer
case isNatural
case descriptors
case keywords
}
let id, flavorGroup, name: String
let isBeer, isSeltzer, isNatural: Bool
let descriptors, keywords: [String]?
}
这是我的视图模型代码:
class ReadData: ObservableObject {
@Published var flavors = [Flavor]()
init(){
loadData()
}
func loadData() {
guard let url = Bundle.main.url(forResource: "flavors", withExtension: "json")
else {
print("Json file not found")
return
}
let data = try? Data(contentsOf: url)
let flavors = try? JSONDecoder().decode([Flavor].self, from: data!)
self.flavors = flavors!
}
}
这是我在查看代码时的最佳尝试:
struct DescriptorListView: View {
@ObservedObject var datas = ReadData()
var body: some View {
List(datas.flavors) { item in
ForEach(item.descriptors, id: \.self) { descriptor in
Text("- \(descriptor)")
}
}
}
}
它会产生这些我不明白如何修复的编译器错误:
可选类型“[String]?”的值?必须解包为“[String]”类型的值
使用“??”合并当可选值包含 'nil'
时提供默认值
使用“!”强制解包如果可选值包含 'nil'
则中止执行
您的尝试非常接近。主要问题是 descriptors
是一个 Optional
。这意味着您必须以某种方式解开该可选值——我使用了 if let
,这是一种称为“可选绑定”的技术。
另一个问题是您当前的代码会在不同的行上列出每个描述符。我使用 joined
将描述符连接在一起,并将它们显示在一行中。
struct DescriptorListView: View {
@ObservedObject var datas = ReadData()
var body: some View {
List(datas.flavors) { item in
HStack {
if let descriptors = item.descriptors {
Text(descriptors.joined(separator: ", "))
} else {
Text("(no data)")
}
}
}
}
}
例如,我如何显示列表中每条记录的描述符,例如:
- 疯狂、果味
- 胖子
- 果味
(请注意,我在模型中将描述符设为可选,因为数组可能为空)
这是我的 JSON 文件代码,来自名为 flavors.json 的文件:
[
{
"id": "U45773",
"flavorGroup": "CASHEW",
"name": "NATURAL CASHEW FLAVORING",
"isBeer": true,
"isSeltzer": true,
"isNatural": true,
"descriptors": ["NUTTY", "FRUITY"],
"keywords": ["aromatic", "fattt-buttery", "brown", "nutty", "roasted", "creamy"]
},
{
"id": "U63639",
"flavorGroup": "BLACK WALNUT",
"name": "NATURAL AND ARTIFICIAL WALNUT FLAVOR",
"isBeer": true,
"isSeltzer": false,
"isNatural": true,
"descriptors": ["FATTY"],
"keywords": ["sweet", "molasses", "woody", "slight dried fruit (amber ale)"]
},
{
"id": "562811",
"flavorGroup": "APRICOT",
"name": "NATURAL AND ARTIFICIAL APRICOT FLAVOR",
"isBeer": true,
"isSeltzer": false,
"isNatural": true,
"descriptors": ["FRUITY"],
"keywords": ["juicy", "skunky", "peach", "floral", "slight green (sierra nevada pale ale)"]
}
]
这是我的模型代码:
struct Flavor: Codable, Identifiable {
enum CodingKeys: CodingKey {
case id
case flavorGroup
case name
case isBeer
case isSeltzer
case isNatural
case descriptors
case keywords
}
let id, flavorGroup, name: String
let isBeer, isSeltzer, isNatural: Bool
let descriptors, keywords: [String]?
}
这是我的视图模型代码:
class ReadData: ObservableObject {
@Published var flavors = [Flavor]()
init(){
loadData()
}
func loadData() {
guard let url = Bundle.main.url(forResource: "flavors", withExtension: "json")
else {
print("Json file not found")
return
}
let data = try? Data(contentsOf: url)
let flavors = try? JSONDecoder().decode([Flavor].self, from: data!)
self.flavors = flavors!
}
}
这是我在查看代码时的最佳尝试:
struct DescriptorListView: View {
@ObservedObject var datas = ReadData()
var body: some View {
List(datas.flavors) { item in
ForEach(item.descriptors, id: \.self) { descriptor in
Text("- \(descriptor)")
}
}
}
}
它会产生这些我不明白如何修复的编译器错误:
可选类型“[String]?”的值?必须解包为“[String]”类型的值
使用“??”合并当可选值包含 'nil'
时提供默认值使用“!”强制解包如果可选值包含 'nil'
则中止执行您的尝试非常接近。主要问题是 descriptors
是一个 Optional
。这意味着您必须以某种方式解开该可选值——我使用了 if let
,这是一种称为“可选绑定”的技术。
另一个问题是您当前的代码会在不同的行上列出每个描述符。我使用 joined
将描述符连接在一起,并将它们显示在一行中。
struct DescriptorListView: View {
@ObservedObject var datas = ReadData()
var body: some View {
List(datas.flavors) { item in
HStack {
if let descriptors = item.descriptors {
Text(descriptors.joined(separator: ", "))
} else {
Text("(no data)")
}
}
}
}
}