Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
427 views
in Technique[技术] by (71.8m points)

swift - iOS: How to pass a model from view model to view model using MVVM?

Suppose I have a model, Car, that is instantiated in ViewModel1 with the following initial properties:

ViewModel1

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

Then I require additional information of the car to be completed in the next view controller. What is the correct way to pass a model between view controllers when following MVVM?

Using MVC, it is simple to do since the view can have reference to the model:

vc2.car = car

Below is a pseudo attempt at the problem, however I am under the impression that a view model should be private and only accessible to a single view controller. Therefore, the below attempt seems incorrect to me.

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
}

I am wondering if what I have shown above is a fine way of doing things when using MVVM, or if not, what is the best way to pass the car between view controllers?

EDIT

This question does not have to do with Class vs Struct. The MVC example above implied it is going to be a class (since it is a reference) and it is being passed between multiple view controllers to complete more parts of the object.

It is a question of how to pass models between view controllers when following MVVM and whether view models should be private to the view controller.

With MVVM, the view controller should not reference the model, therefore should not have a variable var car: Car?. Therefore, you should not see:

let vc2 = ViewController2()
vc2.car = car

Would it be incorrect to see this?

let vc2 = ViewController2()
vc2.viewModel.car = car
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This question has nothing to do with RxSwift, or even MVVM vs MVC. This is a Class vs Struct question. (Note that your comment "Using MVC, it is simple to do since the view can have reference to the model" is not correct when the model is a struct, because you can't pass references to structs.)

How you solve this problem is entirely dependent on how you transition from view controller to view controller.

When view controllers are in charge of the transition.

When view controllers are in charge of the transition, each view controller would be in charge of making the next view controller and each view model would be in charge of making the next view model. Passing models back is done by having the "parent" view model listen to the "child" view model (through either a delegate, callback closure or reactive observable.)

View controllers can make the transition either through segues or "the old fashioned way" by creating and presenting the next view controller directly, or reaching up to it's container view controller (navigation VC for example) and telling it to make the transition.

When coordinators are in charge of the transition.

A new trend in transitioning is to have a coordinator class take care of it instead of the view controllers. Using this idea, the coordinator holds the model, and creates view controllers as needed. The view models then talk back to the coordinator instead of (possibly creating and) talking to each other. This way, view controllers are independent of each other.

You can have the view models talk back to the coordinator using any of delegates, closure callbacks or Rx Observables.


Update from your edit:

You asked if it would be incorrect to have let vc2 = ViewController2(); vc2.viewModel.car = car. The answer is yes, that would be incorrect, but close.

If view controllers are in charge of the transitions, then you would see is this instead:

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

If you are using coordinators, then you would see something like:

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

The key idea behind the view model is not that it's private, it doesn't have to be. The key idea is that it is the only non-view object that the view controller holds on to. You can think of it as a "model controller."


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...