iOS:如何使用MVVM将模型从视图模型传递到视图模型?

时间:2017-05-06 00:45:07

标签: ios swift mvvm

假设我有一个模型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

2 个答案:

答案 0 :(得分:14)

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

如何解决此问题完全取决于您从视图控制器转换到视图控制器的方式。

当视图控制器负责转换时。

当视图控制器负责转换时,每个视图控制器将负责制作下一个视图控制器,并且每个视图模型将负责制作下一个视图模型。通过让“父”视图模型监听“子”视图模型(通过委托,回调闭包或反应可观察对象)来完成传递模型。

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

协调员负责过渡时。

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

您可以使用任何委托,闭包回调或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)

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

答案 1 :(得分:3)

长话短说。只需将模型包装在child视图模型中。

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let detailsViewModel = viewModel.detailsViewModel(for: indexPath.row)
    let detailsViewController = DetailsViewController(viewModel: detailsViewModel) 
    present(detailsViewController, animated: true, completion: nil)
}

detailsViewModel视图模型中声明的master如下:

func detailsViewModel(for index: Int) -> DetailsViewModel {
    return DetailsViewModel(car: cars[index])
}

没有使用协调员。