swiftUi : 2 Pickers on one screen - app crash with “Index out of range”

妖精的绣舞 提交于 2020-06-22 13:08:29

问题


When I try to put 2 pikers with a different number of rows on-screen with different observers. if I select in one number of the row that not exists in the second, when I move to the second picker app crash with this message: "Fatal error: Index out of range"

public enum kTrackType {
    case audio
    case text
}

class kTrack: NSObject, Identifiable {
    public var id = UUID()
    public var trakcId: String
    public var title: String
    public var type: kTrackType

    public init(id: String, title: String, type: kTrackType) {

        self.trakcId = id
        self.title = title
        self.type = type
    }
}

and this is the main struct:

struct SelectedAudioAndSubtileView: View {

let geometry: GeometryProxy

@State var subtitlesList = [kTrack(id: "t0", title: "None", type: kTrackType.text),
                            kTrack(id: "t1", title: "En", type: kTrackType.text),
                            kTrack(id: "t2", title: "Rus", type: kTrackType.text),
                            kTrack(id: "t3", title: "Spn", type: kTrackType.text)]

@State var multiAudioList =  [kTrack(id: "s0", title: "En", type: kTrackType.audio),
                              kTrack(id: "s1", title: "Rus", type: kTrackType.audio)]

@Binding var showSubtitlesPicker: Bool

@State private var selectedAudioPicker: Int = 0

@State private var selectedSubtitlePicker: Int = 0

@State private var selectedType = 0

var body: some View {
    VStack {
        Picker(selection: $selectedType, label: EmptyView()) {
            Text("Audio").tag(0)
            Text("Subtitle").tag(1)
        }
        .pickerStyle(SegmentedPickerStyle())

        Text(self.selectedType == 0 ? "Select Audio" : "Select Subtitle")
        Divider()

        if selectedType == 0 {
            Picker(selection: self.$selectedAudioPicker, label: Text("")) {

                ForEach(self.multiAudioList, id: \.id){ name in
                    Text(name.title)
                }
            }
        } else {
           Picker(selection: self.$selectedSubtitlePicker, label: Text("")) {
                ForEach(self.subtitlesList, id: \.id){ name in
                    Text(name.title)
                }
            }
        }
        Divider()
    }
    .background(Color(#colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1)))
    .offset(y: geometry.size.height - 330)
}

After recheck, the crash happened also if you have same rows in 2 pickers!


回答1:


Here is the situation :

a) the selectedValue should match the tag value, therefore in ForEach, it's better to use index not the id so that you can add tag for each items.

b) the ForEach structure is a complex one and usually to be reused for performance. So in order to force it refresh, id() modifier can be added to extra ForEach structures. There must be one ForEach without id which provides the real underlying data layer.

if selectedType == 0 {
    Picker (selection: self.$selectedAudioPicker, label: Text("")) {
        ForEach(0..<self.multiAudioList.count){ index in
            Text(self.multiAudioList[index].title).tag(index)
        }
    }

} else if  selectedType == 1 {
    Picker(selection: self.$selectedSubtitlePicker, label: Text("")) {
        ForEach(0..<self.subtitlesList.count){ index in
            Text(self.subtitlesList[index].title).tag(index)
        }.id(0)
    }
}


来源:https://stackoverflow.com/questions/59053383/swiftui-2-pickers-on-one-screen-app-crash-with-index-out-of-range

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!