SwiftUI иерархический пикер с динамическими данными c - PullRequest
1 голос
/ 21 февраля 2020

Я пытаюсь использовать несколько сборщиков с динамическими данными c в SwiftUI (XCode 11.3.1). Приложение иногда падает, а иногда зависает или показывает неверные данные в средстве выбора как в симуляторе, так и на реальном устройстве, работающем iOS 13.3.1. Я попробовал предложения в ответах на этот вопрос безуспешно. Что я делаю не так?

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)
                }
            }
        }
    }
}

1 Ответ

1 голос
/ 21 февраля 2020

Используя тот же код, который указан в ссылке, упомянутой в вашем вопросе, я внес небольшие изменения, чтобы принять код для ваших нужд

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")
        }
    }
}

Пожалуйста, обратите внимание, что в форме нет VStack, но есть раздел! Результат работает как положено. (остальной код без каких-либо изменений). Попробуйте код на реальном устройстве (из-за известной ошибки "кнопка назад" в симуляторе)

enter image description here

В случае, если у вас возникли проблемы с остальным кодом вот это

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] = [:]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...