带有动态数据崩溃的SwiftUI分层选择器

问题描述 投票:0回答:1

我刚开始使用SwiftUI,但在管理带有动态数据的多个Picker时遇到了一些困难。在这种情况下,有两个选择器,分别用于CountryCity。当我尝试从一个城市比另一个城市多的国家/地区切换选择器时,该应用程序将崩溃:

致命错误:索引超出范围

任何想法我该如何解决?

App Screenshot

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()
        }
    }
}
swift dynamic swiftui picker
1个回答
0
投票

诀窍是在选择其他国家时“重新创建”“从属”选择器

这是“完整”的单一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()
    }
}

在这里您可以看到结果enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.