问题
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