带有动态数据的 SwiftUI 分层选择器 [英] SwiftUI hierarchical Picker with dynamic data

查看:24
本文介绍了带有动态数据的 SwiftUI 分层选择器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 SwiftUI (XCode 11.3.1) 中使用多个带有动态数据的选择器.该应用程序有时会崩溃,有时会冻结或在模拟器和运行 iOS 13.3.1 的真实设备上的选择器中显示错误的数据.我尝试了

如果您对其余代码有一些问题,这里是

导入基础导入 SwiftUI结构国家:可识别{变量 ID:整数 = 0变量名:字符串var 城市:[城市]}结构城市:可识别{变量 ID:整数 = 0变量名:字符串}类模型:ObservableObject {让国家:[国家] = [国家(ID:0,名称:美国",城市:[城市(ID:0,名称:纽约"),城市(ID:1,名称:洛杉矶"),City(id: 2, name: "Dallas"),City(id: 3, name: "Chicago")]),Country(id: 1, name: "France", city: [City(id: 0,名称:巴黎")])]@Published var selectedContry: Int = 0 {将设置{打印(国家改变",新价值,城市选择[新价值]??0)selectedCity = citySelections[newValue] ??0id = UUID()}}@Published var id: UUID = UUID()@Published var selectedCity: Int = 0 {将设置{DispatchQueue.main.async { [newValue] in打印(城市改变",新值)self.citySelections[self.selectedContry] = newValue}}}var countryNemes: [字符串] {country.map {(国家)在国家的名字}}var cityNamesCount: Int {cityNames.count}var cityNames: [字符串] {country[selectedContry].cities.map { (city) in城市名称}}私人 var citySelections: [Int: Int] = [:]}

I am trying to use multiple pickers with dynamic data in SwiftUI (XCode 11.3.1). The app sometimes crashes and sometimes freezes or shows the wrong data in the picker both in the simulator and on a real device running iOS 13.3.1. I tried the suggestions in the answers to this question with no success. What am I doing wrong?

import SwiftUI

struct DbItem : Identifiable {
    var id: Int
    var name: String
}

final class DbStore : ObservableObject {

    let countries: [DbItem] = [DbItem(id: 0, name: "USA"), DbItem(id: 1, name: "France")]
    let citymap:[Int:[DbItem]] = [0:[DbItem(id: 10, name: "New York"), DbItem(id: 11, name: "Los Angeles"), DbItem(id: 12, name: "Dallas"), DbItem(id: 13, name: "Chicago")], 1:[DbItem(id: 20, name: "Paris"), DbItem(id: 21, name: "Nice"), DbItem(id: 22, name: "Lille")]]

    @Published var cities = [DbItem]()
    @Published var country : Int = -1 {
        willSet {
            if newValue >= 0 {
                self.id = UUID()
                DispatchQueue.main.async { [newValue] in
                    self.cities = self.citymap[newValue]!
                }
            }
        }
    }
    @Published var city : Int = -1 {
        didSet {
        }
    }
}

struct ContentView: View {
    @EnvironmentObject private var store: DbStore

    var body: some View {
        NavigationView {
            Form {
                VStack {
                    Picker(selection: $store.country,
                           label: Text("Country: ")
                    ) {
                        ForEach(store.countries) { country in
                            Text(country.name)
                        }
                    }
                    Picker(selection: $store.city,
                           label: Text("City: ")
                    ) {
                        ForEach(store.cities) { city in
                            Text(city.name)
                        }
                    }
                    .disabled(store.country < 0)
                }
            }
        }
    }
}

解决方案

Using the same code as provided in link mentioned in your question I made some small changes to adopt the code for your needs

struct ContentView: View {
    @ObservedObject var model = Model()
    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Header").font(.title)) {
                    Picker(selection: $model.selectedContry, label: Text("Country")){
                        ForEach(0 ..< model.countryNemes.count){ index in
                            Text(self.model.countryNemes[index])
                        }
                    }
                    Picker(selection: $model.selectedCity, label: Text("City")){
                        ForEach(0 ..< model.cityNamesCount){ index in
                            Text(self.model.cityNames[index])
                        }
                        }
                    .id(model.id)
                }
            }.navigationBarTitle("Navigation Title")
        }
    }
}

Please see, that there is no VStack but Section in the Form! The result works as expected. (the rest of code is without any changes). Try the code on real device (due the known "back button" bug in simulator)

In case you have some trouble with the rest of code, here it is

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 {
            print("country changed", newValue, citySelections[newValue] ?? 0)
            selectedCity = citySelections[newValue] ?? 0
            id = UUID()
        }
    }
    @Published var id: UUID = UUID()
    @Published var selectedCity: Int = 0 {
        willSet {
            DispatchQueue.main.async { [newValue] in
                print("city changed", newValue)
                self.citySelections[self.selectedContry] = newValue
            }
        }
    }
    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
        }
    }

    private var citySelections: [Int: Int] = [:]
}

这篇关于带有动态数据的 SwiftUI 分层选择器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆