Средство обновления при обновлении ObservedObject - PullRequest
1 голос
/ 10 октября 2019

Я пытаюсь динамически добавлять новые строки в Picker следующим образом:

class ViewModel: ObservableObject {    
    @Published private (set) var drinks = ["Tea", "Coffee", "Wine"]

    func addDrink(_ drink: String) {
        drinks.append(drink)
    }
}

struct PickerTest: View {

    @State private var selectedDrink = "Tea"
    @State private var customDrink = ""
    @ObservedObject private var viewModel = ViewModel()

    var body: some View {
        VStack {
            HStack {
                TextField("Enter a drink", text: $customDrink)
                Spacer()
                Button("Add") {
                    self.viewModel.addDrink(self.customDrink)
                }
            }
            Picker("Drinks", selection: $selectedDrink) {  // Removing the wrapping Picker works
                ForEach(viewModel.drinks, id: \.self) { drink in
                    Text(drink)
                }
            }
        }.padding().labelsHidden()
    }
}

Это не работает. Если я удалю Picker, обертывающий ForEach, ForEach обновится, как и ожидалось.

Есть ли способ динамического обновления Picker?

1 Ответ

2 голосов
/ 10 октября 2019

Похоже, ошибка Picker s - я надеюсь, что Apple исправит ее в будущих выпусках SwiftUI.

Я нашел безобразный (мне это действительно не нравится) обходной путьдля этой проблемы:

class ViewModel: ObservableObject {
    @Published var selectedDrink = "Tea"
    @Published var drinks = ["Tea", "Coffee", "Wine"]
    @Published var drinksChanged = true

    func addDrink(_ drink: String) {
        drinks.append(drink)
        drinksChanged.toggle()
    }
}

struct DrinksPicker: View {
    @ObservedObject var viewModel: ViewModel

    var body: some View {
        Picker("Drinks", selection: $viewModel.selectedDrink) {
            ForEach(viewModel.drinks, id: \.self) { drink in
                Text(drink)
            }
        }
    }
}

struct PickerTest: View {
    @State private var customDrink = ""
    @ObservedObject private var viewModel = ViewModel()

    var body: some View {
        VStack {
            HStack {
                TextField("Enter a drink", text: $customDrink)
                Spacer()
                Button("Add") {
                    self.viewModel.addDrink(self.customDrink)
                    self.customDrink = ""
                }
            }
            if viewModel.drinksChanged {
                DrinksPicker(viewModel: viewModel)
            } else {
                DrinksPicker(viewModel: viewModel)
            }
        }.padding().labelsHidden()
    }
}

Вы также можете скрыть это if - else в каком-то другом контейнере:

struct DrinksPickerContainer: View {
    @ObservedObject var viewModel: ViewModel

    var body: some View {
        Group {
            if viewModel.drinksChanged {
                DrinksPicker(viewModel: viewModel)
            } else {
                DrinksPicker(viewModel: viewModel)
            }
        }
    }
}

и затем использовать только DrinksPickerContainer(viewModel: viewModel) в PickerTest

...