带有动态数组的 SwiftUI 多个选择器,索引超出范围错误
SwiftUI multiple pickers with dynamic arrays, index out of range error
原始问题:我需要加载 3 个选择器,每个后续选择器的选择取决于它之前的选择 - 并且每个后续数组都是根据 (a) 先前的选择和 (b) 动态生成的) 一个包含大约 500 个对象的数据库。
- 选择器一工作正常,因为它的选项数组没有改变
并且只依赖于数据文件。
- 选择器二工作正常,因为它严格按照
选择器 1.
- 但是,选择器 3 需要知道选择器 2 中的选项才能按顺序进行
生成它的选项。但是选择器 2 中的选项是根据选择器 1 中的选择动态生成的。
因此,如果选择器 1 中的选择发生变化,导致选择器 2 中的(选择)数组的长度小于提供给选择器 3 的特定选择,程序会因超出范围错误而崩溃。我完全理解为什么会发生崩溃(很清楚)。但似乎我在这里尝试实现的目标是相当普遍的,并且应该有一个解决方案。我能找到的所有解决方案都处理可以提前修复选择器数组的情况(例如,重复出现的 Country/City 示例)。
在这里回答我自己的问题,并进行更新,因为我找到了一个更简单、更稳定的解决方案。该解决方案需要一些要素:
- 正如 New Dev 所建议的那样,数据结构必须是
构建使得选择器元素相互连接。
我最初派生了三个不同的数组。当一个
动态更新没有什么可以追踪他们的关系。所以我创建了一个数据结构,其中较高的选择(例如品牌)包含较低的选择(例如型号和年份)。
- 此外,数组的索引不能直接绑定到每个选择器中的选项。这里的解决方案是创建第二组绑定 Ints,遵循这里的答案:
这是最终结果,我现在已经对其进行了广泛的测试并且它完全稳定。
struct ContentView: View {
@State private var brands: [Brand] = getBrands()
@State private var choice1 = 0
@State private var coice2 = 0
@State private var choice3 = 0
var body: some View {
let chosenBrand = Binding<Int>(get: {
return self.choice1
}, set: {
self.choice1 = [=10=]
self.choice2 = 0
self.choice3 = 0
})
let chosenModel = Binding<Int>(get: {
return self.choice2
}, set: {
self.choice2 = [=10=]
self.choice3 = 0
})
let chosenYear = Binding<Int>(get: {
return self.choice3
}, set: {
self.choice3 = [=10=]
})
return
VStack {
Picker(selection: chosenBrand, label: Text("Brand")) {
ForEach(self.brands.indices, id: \.self) { index in
Text(self.brands[index].name).tag(index)
}
}
Picker(selection: chosenModel, label: Text("Model")) {
ForEach(self.brands[choice1].models.indices, id: \.self) { index in
Text(self.brands[self.choice1].models[index].name).tag(index)
}
}
Picker(selection: chosenYear, label: Text("Year")) {
ForEach(self.brands[choice1].models[choice2].years).indices, id: \.self) { index in
Text(self.brands[self.choice1].models[self.choice2].years[index].description).tag(index)
}
}
}
}
}
原始问题:我需要加载 3 个选择器,每个后续选择器的选择取决于它之前的选择 - 并且每个后续数组都是根据 (a) 先前的选择和 (b) 动态生成的) 一个包含大约 500 个对象的数据库。
- 选择器一工作正常,因为它的选项数组没有改变 并且只依赖于数据文件。
- 选择器二工作正常,因为它严格按照 选择器 1.
- 但是,选择器 3 需要知道选择器 2 中的选项才能按顺序进行 生成它的选项。但是选择器 2 中的选项是根据选择器 1 中的选择动态生成的。
因此,如果选择器 1 中的选择发生变化,导致选择器 2 中的(选择)数组的长度小于提供给选择器 3 的特定选择,程序会因超出范围错误而崩溃。我完全理解为什么会发生崩溃(很清楚)。但似乎我在这里尝试实现的目标是相当普遍的,并且应该有一个解决方案。我能找到的所有解决方案都处理可以提前修复选择器数组的情况(例如,重复出现的 Country/City 示例)。
在这里回答我自己的问题,并进行更新,因为我找到了一个更简单、更稳定的解决方案。该解决方案需要一些要素:
- 正如 New Dev 所建议的那样,数据结构必须是 构建使得选择器元素相互连接。 我最初派生了三个不同的数组。当一个 动态更新没有什么可以追踪他们的关系。所以我创建了一个数据结构,其中较高的选择(例如品牌)包含较低的选择(例如型号和年份)。
- 此外,数组的索引不能直接绑定到每个选择器中的选项。这里的解决方案是创建第二组绑定 Ints,遵循这里的答案:
这是最终结果,我现在已经对其进行了广泛的测试并且它完全稳定。
struct ContentView: View {
@State private var brands: [Brand] = getBrands()
@State private var choice1 = 0
@State private var coice2 = 0
@State private var choice3 = 0
var body: some View {
let chosenBrand = Binding<Int>(get: {
return self.choice1
}, set: {
self.choice1 = [=10=]
self.choice2 = 0
self.choice3 = 0
})
let chosenModel = Binding<Int>(get: {
return self.choice2
}, set: {
self.choice2 = [=10=]
self.choice3 = 0
})
let chosenYear = Binding<Int>(get: {
return self.choice3
}, set: {
self.choice3 = [=10=]
})
return
VStack {
Picker(selection: chosenBrand, label: Text("Brand")) {
ForEach(self.brands.indices, id: \.self) { index in
Text(self.brands[index].name).tag(index)
}
}
Picker(selection: chosenModel, label: Text("Model")) {
ForEach(self.brands[choice1].models.indices, id: \.self) { index in
Text(self.brands[self.choice1].models[index].name).tag(index)
}
}
Picker(selection: chosenYear, label: Text("Year")) {
ForEach(self.brands[choice1].models[choice2].years).indices, id: \.self) { index in
Text(self.brands[self.choice1].models[self.choice2].years[index].description).tag(index)
}
}
}
}
}