SwiftUI 和 MVVM - 将数据从子视图的 ViewModel 传递到父视图的 ViewModel

时间:2021-07-12 01:51:01

标签: swift mvvm swiftui

我想知道当一个 View 是另一个 View 的父级时,如何在 SwiftUI 应用程序中将数据从一个 ViewModel 传递到另一个 ViewModel,但 ViewModel 没有任何连接。

CarShowView(使用 CarShowViewModel) 当用户点击按钮时,显示一张 CarSearchView(使用 CarSearchViewModel)。

CarSearchViewModel 有一个 allCars 数组,用户可以从中选择一个 Car。然后,这辆车应该被添加到 CarShowViewModel 中的 newCars 数组中。

如果我只需要抢一辆车。但用户可能会打开 SearchView,选择一辆车将其添加到 newCars,然后重新打开搜索视图并选择另一辆车添加到 newCars。

我需要在视图中以某种方式拥有这个逻辑吗?或者有没有办法可以使用这些 ViewModel 相互交谈?与此相关的问题有很多,但我还没有找到专门解决此案例的问题。

class CarShowViewModel: ObservableObject {
     @Published var newCars: [Car]
}
class CarShowView: View {
     @ObservedObject var carShowVM = CarShowViewModel()



     var body: some View {
          // body
     }.sheet(isPresented: $showAllCars) {
          CarSearchView(carSearchVM: CarSearchViewModel())
     }
}
class CarSearchViewModel: ObservableObject {
     @Published var chosenCar: Car? = nil
     @Published var allCars: [Car]

     // repository to grab all cars
     var carRepository: CarRepository

     func save(car: Car) {
          // should save the car I select as chosenCar and close the CarSearch. Somehow I need this to pass the car chosen to CarShowViewModel.
     }
}
class CarSearchView {
     @ObservedObject var carSearchVM: CarSearchViewModel

}

1 个答案:

答案 0 :(得分:1)

实现此目的的一种方法是使用传递给第二个视图模型的回调函数,该函数可以在父视图中执行一些代码。类似的东西:

class CarSearchViewModel: ObservableObject {
    @Published var chosenCar: Car? = nil
    @Published var allCars: [Car]
    
    var saveCallback: (Car) -> Void
    var carRepository: CarRepository
    
    init(carRepository: CarRepository, saveCallback: @escaping (Car) -> Void) {
        self.carRepository = carRepository
        self.saveCallback = saveCallback
    }
    
    func save(car: Car) {
        self.saveCallback(car)
    }
}

class CarShowViewModel: ObservableObject {
     @Published var newCars: [Car] = []
}

struct CarShowView: View {
    @ObservedObject var carShowVM = CarShowViewModel()
    @State private var showAllCars = false
    
     var body: some View {
          Text("Hello, world!")
            .sheet(isPresented: $showAllCars) {
                CarSearchView(carSearchVM:
                                CarSearchViewModel(carRepository: CarRepository(), //not sure where this is coming from
                                                   saveCallback: { car in
                                                    carShowVM.newCars = [car] //or whatever should be here
                                                   }))
            }
     }
}

请注意,我不得不稍微猜测一下这里发生了什么,但这个概念应该是合理的。同样重要的是要注意 SwiftUI View 应该是 struct,而不是类 - 您在代码中错误地标记了它们。


实现此目的的另一种方法是为父视图和子视图提供一个真实来源——基本上,两个视图模型都有一个。当然,这可能会打破严格的 MVVM 模式。

您也可以通过Combine 和Publishers 实现这一点,但我提到的回调方法似乎最简单。