如何将 @EnvironmentObject 与 List 结合使用

how to use a @EnvironmentObject in combination with a List

Anlil 的答案中的基本应用程序代码运行良好。如果我将数据模型编辑得更像我的,使用多维字符串数组,我会得到类似:

import SwiftUI
import Combine

struct ContentView: View {
    @EnvironmentObject var dm: DataManager

    var body: some View {
        NavigationView {
            List {
               NavigationLink(destination:AddView().environmentObject(self.dm)) {
                    Image(systemName: "plus.circle.fill").font(.system(size: 30))
                }
                ForEach(dm.array, id: \.self) { item in
                    NavigationLink(destination: DetailView(item: item)) {
                        Text(item[0])
                    }
                }
            }
        }
    }
}

struct DetailView: View {
    var item : [String] = ["", "", ""]
    var body: some View {
        VStack {
            Text(item[0])
            Text(item[1])
            Text(item[2])
        }
    }
}

struct AddView: View {
    @EnvironmentObject var dm: DataManager
    @State var item0 : String = "" // needed by TextField
    @State var item1 : String = "" // needed by TextField
    @State var item2 : String = "" // needed by TextField
    @State var item : [String] = ["", "", ""]
    var body: some View {
        VStack {
            TextField("Write something", text: $item0)
                    .textFieldStyle(.roundedBorder)
                    .padding(.horizontal)
            TextField("Write something", text: $item1)
                    .textFieldStyle(.roundedBorder)
                    .padding(.horizontal)
            TextField("Write something", text: $item2)
                    .textFieldStyle(.roundedBorder)
                    .padding(.horizontal)
            Button(action: {
                self.item = [self.item0, self.item1, self.item2]
                print(self.item)
                self.dm.array.append(self.item)
            }) {
                Text("Save")
            }
        }
    }
}

class DataManager: BindableObject {
    var willChange = PassthroughSubject<Void, Never>()
    var array : [[String]] = [["Item 1","Item 2","Item 3"],["Item 4","Item 5","Item 6"],["Item 7","Item 8","Item 9"]] {
        didSet {
            willChange.send()
        }
    }
}

没有错误,代码按预期运行。在我要重写我自己的代码之前(根据我学到的 solar 的经验教训),如果可以检查代码就更好了。

我对 SwiftUI 印象深刻!

如果你的 "source of truth" 是一些 "model instances" 的数组,而你只需要读取值,你可以像以前一样传递这些实例:

import SwiftUI
import Combine

struct ContentView: View {
    @EnvironmentObject var dm: DataManager

    var body: some View {
        NavigationView {
            List(dm.array, id: \.self) { item in
                NavigationLink(destination: DetailView(item: item)) {
                    Text(item)
                }
            }
        }
    }
}

struct DetailView: View {
    var item : String
    var body: some View {
        Text(item)
    }
}

class DataManager: BindableObject {
    var willChange = PassthroughSubject<Void, Never>()
    let array = ["Item 1", "Item 2", "Item 3"]
}


#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(DataManager())
    }
}
#endif

仅当某些视图能够操作实例内的数据时,您才需要传递 EnvironmentObject...在这种情况下,您可以轻松更新 EnvironmentObject 的状态,并且所有内容都将在各处自动神奇地更新!

下面的代码显示了一个带有 "list"、"detail" 和 "add" 的基本应用程序,因此您可以看到 'environment' 的运行情况(唯一需要注意的是您有以在点击保存按钮后手动点击 < 返回)。尝试一下,您会看到列表会神奇地更新。

import SwiftUI
import Combine

struct ContentView: View {
    @EnvironmentObject var dm: DataManager

    var body: some View {
        NavigationView {
            List {
               NavigationLink(destination:AddView().environmentObject(self.dm)) {
                    Image(systemName: "plus.circle.fill").font(.system(size: 30))
                }
                ForEach(dm.array, id: \.self) { item in
                    NavigationLink(destination: DetailView(item: item)) {
                        Text(item)
                    }
                }
            }
        }
    }
}

struct DetailView: View {
    var item : String
    var body: some View {
        Text(item)
    }
}

struct AddView: View {
    @EnvironmentObject var dm: DataManager
    @State var item : String = "" // needed by TextField
    var body: some View {
        VStack {
            TextField("Write something", text: $item)
                    .textFieldStyle(.roundedBorder)
                    .padding(.horizontal)
            Button(action: {
                self.dm.array.append(self.item)
            }) {
                Text("Save")
            }
        }
    }
}

class DataManager: BindableObject {
    var willChange = PassthroughSubject<Void, Never>()
    var array : [String] = ["Item 1", "Item 2", "Item 3"] {
        didSet {
            willChange.send()
        }
    }
}


#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(DataManager())
    }
}
#endif