SwiftUI - передавать данные в разные представления

Я работаю над приложением, которое имеет 4 различных представления. Основное представление (ContentView), AddView и EditView. И есть также отдельный DataView с классом, где я передаю все данные ObservableObject в другие представления.

На главном экране у меня есть список предметов. В AddView я добавляю элементы в этот список, а из ContentView я хотел бы иметь возможность редактировать добавленные элементы с помощью навигационной ссылки. Таким образом, в главном окне я хотел бы перейти к EditView, изменить значения и снова вернуться к ContentView, где я вижу измененные значения.

Вы бы использовали ObservableObject для этого или мне нужен EnvironmentObject? Поскольку в данный момент EditView не работает, я не могу передать данные из ContentView в EditView, все текстовые поля в EditView пусты, значения не передаются. Он работает для передачи данных из AddView в ContentView, но не из ContentView в EditView.

Может кто-нибудь сказать мне, как данные должны быть связаны со всеми представлениями?

Всего 1 ответ


Вы должны использовать @EnvironmentObject . Это позволяет обмениваться объектами, что очень важно для обмена данными с другими представлениями.

Я использую объект Shopping в этом примере. Это приложение будет действовать как список покупок. Весь этот проект доступен на GitHub здесь .

Я действительно надеюсь, что это полезно, так как это заняло довольно много времени. Это всего лишь общий пример того, как эффективно использовать @EnvironmentObject между View .

Приложение выглядит так:

Как выглядит приложение


Создание проекта

(можно скачать через GitHub, см. ссылку выше)

1: Сначала в вашем SceneDelegate.swift замените:

let contentView = ContentView()

с:

let contentView = ContentView().environmentObject(Shopping())

2: Xcode сейчас будет жаловаться на то, что Shopping не сделаны, поэтому мы исправим это следующим образом:

class Shopping: ObservableObject {

    @Published var list = [
        ShoppingItem("Bread", quantity: 1),
        ShoppingItem("Milk", quantity: 2),
        ShoppingItem("Eggs", quantity: 12)
    ]

    func addItem(_ item: ShoppingItem) {
        list.append(item)
    }
}


class ShoppingItem: Identifiable {

    var name: String
    var quantity: Int

    init(_ name: String, quantity: Int) {
        self.name = name
        self.quantity = quantity
    }
}

3: Далее нам нужен основной контент, ContentView :

struct ContentView: View {

    @EnvironmentObject private var shopping: Shopping
    @State private var newItem: String?

    var body: some View {
        NavigationView {
            List {
                ForEach(shopping.list) { item in
                    NavigationLink.init(destination: EditView(currentItem: item)) {
                        HStack {
                            Text(item.name)
                            Spacer()
                            Text(String(item.quantity))
                            Spacer().frame(width: 10)
                        }
                    }
                }

                if newItem != nil {
                    TextField("New Item", text: $newItem.bound, onCommit: {
                        if !self.newItem!.isEmpty {
                            self.shopping.addItem(ShoppingItem(self.newItem!, quantity: 1))
                        }
                        self.newItem = nil
                    })
                }
            }
            .navigationBarTitle("Shopping List")
            .navigationBarItems(trailing: Button(action: {
                self.newItem = ""
            }, label: {
                Image(systemName: "plus.circle.fill")
                    .resizable()
                    .frame(width: 25, height: 25)
            }))
        }
    }
}

4: Наряду с этим extension для работы необязательного @State s ( @State здесь , хотя это было упрощено):

extension Optional where Wrapped == String {

    var bound: String {
        get {
            return self ?? ""
        }
        set {
            self = newValue
        }
    }
}

5: И, наконец, - EditView , чтобы вы могли редактировать название товара в списке покупок:

struct EditView: View {

    let currentItem: ShoppingItem
    @EnvironmentObject private var shopping: Shopping
    @State private var name = ""

    var body: some View {
        TextField("Item", text: $name, onCommit: saveName)
            .padding()
            .background(Color.gray)
            .onAppear(perform: setName)
    }

    private func saveName() {
        shopping.objectWillChange.send()
        currentItem.name = name
    }
    private func setName() {
        name = currentItem.name
    }
}

Есть идеи?

10000