如何在 SwiftUI 中的 ViewModel 之间传递数据

Pum*_*lad 6 ios swift swiftui

我有这样的用例,我有一个父视图和一个子视图。两个视图都有自己对应的 ViewModel。

家长视图:

struct ParentView: View {

  @StateObject var parentViewModel = ParentViewModel()

  var body: some View {
    NavigationView {
        List {
            TextField("Add Name", text: $parentViewModel.newListName)
            NavigationLink(destination: ChildView()) {
                Label("Select Products", systemImage: K.ListIcons.productsNr)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

父视图模型:

class ParentViewModel: ObservableObject {

  @Published var newListName: String = ""

  func saveList() {
    // some logic to save to CoreData, method would be called via a button
    // how do I reference "someString" from ChildViewModel in this ViewModel?
  }
}
Run Code Online (Sandbox Code Playgroud)

子视图:

struct ChildView: View {

    @StateObject var childViewModel = ChildViewModel()

    var body: some View {
        NavigationView {
            List{
                Text("Some element")
                    .onTapGesture {
                        childViewModel.alterData()
                    }      
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

子视图模型:

class ChildViewModel: ObservableObject {
    @Published var someString: String = ""

    func alterData() {
       someString = "Toast"
    }
}
Run Code Online (Sandbox Code Playgroud)

我现在的问题是,如何将“someString”的新值从 ChildViewModel 传递到 ParentViewModel,以便用它做一些进一步的事情?我尝试@StateObject var childViewModel = ChildViewModel()在 ParentViewModel 中创建引用,但这显然不起作用,因为这将创建 ChildViewModel 的新实例,因此不知道对“someString”所做的更改


解决方案: 按照 Josh 的建议,我采用了使用单个 ViewModel 而不是两个的方法。为了实现这一点,ParentView 需要一个.environmentObject(T)修饰符。

家长视图:

struct ParentView: View {

  @StateObject var parentViewModel = ParentViewModel()

  var body: some View {
    NavigationView {
        List {
            TextField("Add Name", text: $parentViewModel.newListName)
            NavigationLink(destination: ChildView()) {
                Label("Select Products", systemImage: K.ListIcons.productsNr)
            }
        }
    }.environmentObject(parentViewModel)
}
Run Code Online (Sandbox Code Playgroud)

然后 ChildView 通过@EnvironmentObject不使用初始值设定项来引用该环境对象:

struct ChildView: View {

    @EnvironmentObject var parentViewModel: ParentViewModel

    var body: some View {
        NavigationView {
            List{
                Text("Some element")
                    .onTapGesture {
                        parentViewModel.alterData()
                    }      
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 1

对于这种情况,您很可能会使用绑定:

struct ChildView: View {
    @Binding var name: String

    var body: some View {
        NavigationView {
            List{
                Text("Some element")
                    .onTapGesture {
                        name = "Altered!"
                    }      
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在父级中:

struct ParentView: View {

  @StateObject var parentViewModel = ParentViewModel()

  var body: some View {
    NavigationView {
        List {
            TextField("Add Name", text: $parentViewModel.newListName)
            NavigationLink(destination: ChildView(name: $parentViewModel.newListName)) {
                Label("Select Products", systemImage: K.ListIcons.productsNr)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,我认为您可以NavigationView从 中删除视图ChildView。拥有它就ParentView足够了。