我正在开发一个具有4种不同视图的应用程序。主视图( ContentView ), AddView , EditView 和带有类的单独的 DataView ObservableObject 将所有数据传递到其他视图。
在主视图中,我有一个项目列表。在 AddView 中,我从 ContentView 向该列表添加项目。我希望能够通过使用导航链接来编辑添加的项目。因此,从主视图中,我想转到 EditView ,更改值,然后再次回到 ContentView ,在此我看到更改的值。
您将使用 ObservableObject 还是我需要EnvironmentObject?由于目前 EditView 无法正常工作,因此我无法将数据从 ContentView 传递给 EditView , EditView 为空,不会传递值。它可以将数据从 AddView 传递到 ContentView ,而不是从 ContentView 传递到 EditView 。
有人可以告诉我如何将数据链接到所有视图吗?
答案 0 :(得分:6)
您应该使用@EnvironmentObject
。它允许共享对象,这对于将数据共享给其他视图非常重要。
在此示例中,我正在使用Shopping
对象。该应用程序将像购物清单一样。整个项目可从GitHub here获得。
我真的希望这很有用,因为它花了很长时间。这只是在@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
起作用(信用here,尽管已简化):
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
}
}