一尘不染

iOS:如何使用MVVM在视图模型之间传递模型?

swift

假设我有一个模型Car,该模型在 ViewModel1中 实例化为以下初始属性:

ViewModel1

let car = Car(make: "McLaren", model: "P1", year: 2015)

然后,我需要在下一个视图控制器中完成汽车的其他信息。遵循MVVM时,在视图控制器之间传递模型的 正确 方法是什么?

使用MVC,操作很简单,因为视图可以引用模型:

vc2.car = car

以下是对该问题的伪尝试,但是我给人的印象是视图模型应该是私有的,并且只能由单个视图控制器访问。因此,以下尝试对我来说似乎是不正确的。

ViewController1

fileprivate let viewModel = ViewModel1()

func someMethod() ->  { 
    let car = self.viewModel.car 
    let vc2 = ViewController2()
    vc2.viewModel.car = car
    present(vc2, animated: true, completion: nil)
}

ViewController2

let viewModel = ViewModel2()

func anotherMethod() {
    print(self.viewModel.car.make)  //prints "McLaren"

    viewModel.manipulateCar()       //adds additional information to the car object

    print(self.viewModel.car.color) //prints "Black"

    //Pass the finished car to the last view controller to display a summary
    let vc3 = ViewController3()
    vc3.viewModel.car = self.viewModel.car
}

我想知道上面显示的是使用MVVM时的一种很好的处理方法,或者如果不是,在视图控制器之间传递汽车的 最佳 方法是什么?

编辑

这个问题与Class vs Struct无关。上面的MVC示例暗示它将成为一个类(因为它是引用),并且在多个视图控制器之间传递它以完成对象的更多部分。

这是一个问题,即在遵循MVVM时如何在视图控制器之间传递模型,以及视图模型是否应为视图控制器专用。

使用MVVM,视图控制器不应引用模型,因此不应具有变量var car: Car?。因此,您不应看到:

let vc2 = ViewController2()
vc2.car = car

看到这是不正确的吗?

let vc2 = ViewController2()
vc2.viewModel.car = car

阅读 346

收藏
2020-07-07

共1个答案

一尘不染

这个问题与RxSwift或MVVM vs MVC无关。这是一个Class vs
Struct问题。(请注意,当模型是结构时,您的注释“使用MVC,因为视图可以引用模型,因此很容易做到”是不正确的,因为您不能将引用传递给结构。)

您如何解决此问题完全取决于您如何从视图控制器过渡到视图控制器。

当视图控制器负责过渡时。

当视图控制器负责过渡时,每个视图控制器将负责制作下一个视图控制器,而每个视图模型将负责制作下一个视图模型。通过使“父”视图模型侦听“子”视图模型(通过委托,回调闭包或可观察的响应)来完成传递回模型。

通过直接创建并呈现下一个视图控制器,或者到达其容器视图控制器(例如导航VC)并告诉其进行转换,视图控制器可以通过segue或“老式方式”进行转换。

由协调员负责过渡。

过渡的新趋势是让协调器类代替视图控制器来处理它。使用此想法,协调器保存模型,并根据需要创建视图控制器。然后,视图模型与协调器对话,而不是(可能创建并)彼此对话。这样,视图控制器便彼此独立。

您可以使视图模型使用委托,闭包回调或Rx Observables与协调器进行对话。


根据您的修改进行更新:

您问拥有它是否不正确let vc2 = ViewController2(); vc2.viewModel.car = car。答案是肯定的,那是不正确的,但是很接近。

如果视图控制器负责过渡,那么您将看到的是:

// in view controller 1
let vc2 = ViewController2()
vc2.viewModel = self.viewModel.viewModel2

如果使用协调器,则会看到类似以下内容的信息:

// in coordinator
let vm2 = ViewModel(car: self.car)
let vc2 = ViewController2(viewModel: vm2)

视图模型背后的关键思想不是私有的,不必一定是私有的。关键思想是它是视图控制器持有的唯一非视图对象。您可以将其视为“模型控制器”。

2020-07-07