我刚开始使用SwiftUI,但在管理带有动态数据的多个Picker时遇到了一些困难。在这种情况下,有两个选择器,分别用于Country和City。当我尝试从一个城市比另一个城市多的国家/地区切换选择器时,该应用程序将崩溃:
致命错误:索引超出范围
任何想法我该如何解决?
import SwiftUI
struct Country: Identifiable {
var id: Int = 0
var name: String
var cities: [City]
}
struct City: Identifiable {
var id: Int = 0
var name: String
}
struct ContentView: View {
@State var selectedCountry = 0
@State var selectedCity = 0
let countries: [Country] = [Country(id: 0, name: "USA", cities: [City(id: 0, name: "New York"),City(id: 1, name: "Los Angeles"),City(id: 2, name: "Dallas"),City(id: 3, name: "Chicago")]),Country(id: 1, name: "France", cities: [City(id: 0, name: "Paris")])]
var body: some View {
VStack {
Picker(selection: $selectedCountry,label: Text("")){
ForEach(0 ..< countries.count){ index in
Text(self.countries[index].name)
}
}.labelsHidden()
.clipped()
Picker(selection: $selectedCity,label: Text("")){
ForEach(0 ..< countries[selectedCountry].cities.count){ index in
Text(self.countries[self.selectedCountry].cities[index].name)
}
}.labelsHidden()
.clipped()
}
}
}
诀窍是在选择其他国家时“重新创建”“从属”选择器
这是“完整”的单一View iOS应用,请注意,它将不会在Playground中运行
//
// ContentView.swift
// tmp034
//
// Created by Ivo Vacek on 05/02/2020.
// Copyright © 2020 Ivo Vacek. NO rights reserved.
//
import Foundation
import SwiftUI
struct Country: Identifiable {
var id: Int = 0
var name: String
var cities: [City]
}
struct City: Identifiable {
var id: Int = 0
var name: String
}
class Model: ObservableObject {
let countries: [Country] = [Country(id: 0, name: "USA", cities: [City(id: 0, name: "New York"),City(id: 1, name: "Los Angeles"),City(id: 2, name: "Dallas"),City(id: 3, name: "Chicago")]),Country(id: 1, name: "France", cities: [City(id: 0, name: "Paris")])]
@Published var selectedContry: Int = 0 {
willSet {
selectedCity = 0
id = UUID()
print("country changed")
}
}
@Published var id: UUID = UUID()
@Published var selectedCity: Int = 0
var countryNemes: [String] {
countries.map { (country) in
country.name
}
}
var cityNamesCount: Int {
cityNames.count
}
var cityNames: [String] {
countries[selectedContry].cities.map { (city) in
city.name
}
}
}
struct ContentView: View {
@ObservedObject var model = Model()
var body: some View {
return VStack {
Picker(selection: $model.selectedContry, label: Text("")){
ForEach(0 ..< model.countryNemes.count){ index in
Text(self.model.countryNemes[index])
}
}.labelsHidden()
.clipped()
Picker(selection: $model.selectedCity, label: Text("")){
ForEach(0 ..< model.cityNamesCount){ index in
Text(self.model.cityNames[index])
}
}
// !! changing views id force SwiftUI to recreate it !!
.id(model.id)
.labelsHidden()
.clipped()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}