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

Posted

技术标签:

【中文标题】具有动态数组的 SwiftUI 多个选择器,索引超出范围错误【英文标题】:SwiftUI multiple pickers with dynamic arrays, index out of range error 【发布时间】:2020-08-03 19:16:36 【问题描述】:

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

选择器一工作正常,因为它的选项数组没有改变 并且仅依赖于数据文件。 选择器 2 工作正常,因为它严格按照 选择器 1。 然而,选择器 3 需要知道选择器 2 中的选择才能按顺序 生成它的选项。但是选择器 2 中的选项是根据选择器 1 中的选择动态生成的。

因此,如果选择器 1 中的选择发生变化,使得选择器 2 中的(选择)数组的长度小于提供给选择器 3 的特定选择,则程序会因超出范围错误而崩溃。我完全理解为什么会发生崩溃(很清楚)。但似乎我在这里试图实现的目标相当普遍,应该有一个解决方案。我能找到的所有解决方案都处理可以提前修复选择器数组的实例(例如反复出现的 Country/City 示例)。

【问题讨论】:

这里没有直接的解决方案。您需要避免在错误索引处访问数组的情况。我建议有一个视图模型,其中每个选择器都需要在每次更改时正确填充 @Published 数组。然后遍历数组,而不是索引:ForEach(models, id: \.self) ... 。基本上,设计你的模型,就好像没有选择器一样——只有一些改变选择的功能,并使 起作用;然后将其连接到选择器 感谢您的回复。你说的很有道理,尽管我在尝试实施它时遇到了最困难的时间。我可以创建空的@Published 数组,但我认为我想要的是工作的、更新的填充数组。但是,每当我尝试(在我的视图之外工作)通过调用我的函数来用数据填充数组时,我最终都会遇到关于在初始化之前使用 self 的编译器错误。我对 swift 很陌生,我真的不知道何时何地可以调用函数:我不能在课堂上这样做,但我不想在视图中这样做。这让我不知所措。 【参考方案1】:

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

    正如 New Dev 的有益建议,数据结构必须是 构造使得拾取器元素相互连接。 我最初派生了三个不同的独立数组。当一个 动态更新,没有任何东西可以跟踪他们的关系。所以我创建了一个数据结构,其中较高的选择(例如品牌)包含较低的选择(例如型号和年份)。 此外,数组的索引不能直接绑定到每个选择器中的选项。这里的解决方案是按照这里的答案创建第二组绑定 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)
                    
                
            
        
    

【讨论】:

以上是关于具有动态数组的 SwiftUI 多个选择器,索引超出范围错误的主要内容,如果未能解决你的问题,请参考以下文章

具有多个组件的动态 PickerView:索引超出范围

SwiftUI - 动态分段选取器过滤器

表单中的 SwiftUI 选择器 - 索引超出范围

来自先前选择器的选择器值 - CoreData/SwiftUI

基于具有唯一值的数组创建多个动态选择过滤器以过滤 Vue.js 中的另一个数组

设置连续轮选择器 - SwiftUI