SwiftUI具有动态数组的多个选择器,索引超出范围错误

时间:2020-08-03 19:16:36

标签: swift swiftui picker

原始问题:我需要加载3个选择器,每个后续选择器的选择取决于之前的选择器-并且每个后续数组都是基于(a)先前选择和(b)a动态生成的大约500个对象的数据库。

  • 选择器一正常工作,因为它的选项数组不变 并且仅取决于数据文件。
  • 选择器2正常工作,因为它严格按照更新 选择器1。
  • 选择器3,但是,需要知道选择器2中的选择顺序 生成其选项。但是选择器2中的选项是根据选择器1中的选择动态生成的。

因此,如果选择器1中的选择发生更改,使得选择器2中的数组(选择)的长度小于馈给选择器3的特定选择,则程序将崩溃,并出现超出范围的错误。我完全理解崩溃发生的原因(很明显)。但是似乎我要在这里实现的目标相当普遍,应该有一个解决方案。我能找到的所有解决方案都涉及可以预先修复选择器数组的实例(例如,反复出现的“国家/城市”示例)。

1 个答案:

答案 0 :(得分:1)

在这里回答我自己的问题,并不断更新,因为我找到了一个更简单,更稳定的解决方案。该解决方案需要许多要素:

  1. 正如New Dev所建议的那样,数据结构必须 构造使得拾取器元件彼此连接。 我最初以不同的方式派生了三个单独的数组。当一个 动态更新,没有任何东西可以追踪他们的关系。因此,我创建了一个数据结构,其中较高的选择(例如品牌)包含较低的选择(例如型号和年份)。
  2. 此外,数组的索引不能直接绑定到每个选择器中的选择。此处的解决方案是按照此处的答案创建第二组绑定Ints:SwiftUI Picker onChange or equivalent?

这是最终结果,我已经对其进行了广泛测试,并且它完全稳定。

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 = $0
                    self.choice2 = 0
                    self.choice3 = 0
                })
        
        let chosenModel = Binding<Int>(get: {
                    return self.choice2
                }, set: {
                    self.choice2 = $0
                    self.choice3 = 0
                })
        
        let chosenYear = Binding<Int>(get: {
                    return self.choice3
                }, set: {
                    self.choice3 = $0
                })
    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)
                    }
                }
            }
        }
    }