Mugunth
Mugunth

Reputation: 14499

Why use a View Model (MVVM) in iOS?

Because, Swift/Objective-C supports writing extensions, I write my "ViewModel" properties in an extension class on the model and use this extension in places where one normally uses a ViewModel.

I know extensions can't have stored properties. But most MVVM architectures don't recommend stored properties in ViewModel (except those used for caching) anyways.

My main trouble with maintaining separate ViewModel object is getting it in sync with the model. Yes, there are plenty of third-party frameworks to help sync using reactive programming techniques. But for what can be solved, by simply using an extension, why use a heavy framework achieve the same?

I've not hit a road block with my extensions based MVVM architecture. Have anyone of you tried this and moved on to a reactive programming architecture?

Upvotes: 3

Views: 2417

Answers (3)

Mike Sand
Mike Sand

Reputation: 2770

My bad experience with the extensions approach was the basis for the first and most important part of my March 2016 talk at iOSoHo in New York. Most of what I said about extensions is not in the slides. There are several issues with the extension approach:

  1. You can only ever have one mapping of a model to a view (without another intermediate layer to provide that logic coordinating extension properties). This greatly impairs view reusability.
  2. Regarding point 1, even if you do coordinate around this, you're likely to get collisions if you're using the model many places, for example a name and then later adding firstNameOnly, etc. Definitely a model can only ever conform to a protocol one way, if you're tempted to go that way.
  3. Providing dummy values in lieu of the model, for doing auto layout, debugging, error cases, etc., is almost impossible. You'll probably find yourself writing a struct for that--that's a ViewModel.
  4. If you have a view that needs multiple models to populate it, or needs info outside the model, a view model simplifies their coordination.

With a ViewModel these important cases become trivial. (In the talk I call "commands" because they perfectly match the Gang of Four Design Patterns definition of command; Design Patterns notes also known as Action, i.e. UIAlertAction.)

I take the approach that a "ViewModel" should be lightweight, immutable, and distributed through unidirectional data flow. They have stored properties but but this is just to move data around, the VMs themselves are immutable and disposable. This is similar to the approach mentioned by Facebook at iOSoHo March 2017, though I think they don't call them View Models, just lightweight objects. You could put more complex logic in there but really best to, at most, call out to more complex logic handled elsewhere.

One addition I think is key, my rule is that a "ViewModel", whatever you call it, should have no properties that can't be written by a programmer looking at wireframes. So a var dateString : String not var date : NSDate. This is my cheeky term in the slides, "Modal Object Attribute Transformer". But it's mnemonic for a serious point: A castle needs to be able to raise the drawbridge and carry on when under siege; a view needs to be fully functional when the network is cut off (or doesn't yet exist). You will have much easier time in so many scenarios than if your view can do that.

Just a few weeks ago I took this approach and was able to create multiple complex screens in about 4 days, working only from designs, that will eventually be populated by data from the network but currently without any model or networking layer whatsoever. When the data layer is ready, I can simply write some creational methods init(with: Model) or better static func withModelforCase1(_ model: Model) -> ViewModel and write the mapping in the creation method, then when the model is connected, replace static func debugCase1() -> ViewModel with these creation methods. As the model evolves the compiler will throw errors here and only here; as the view evolves, adjust the ViewModel, and again the compiler will throw errors here and only here. No other code would need to be touched.

Extensions seem very elegant at the start, but actually create a tight coupling between models and views. Some kind of ViewModel approach is a robust system the needs of modern iOS apps--and modern iOS app development.

Upvotes: 3

Vishnu Prasannan
Vishnu Prasannan

Reputation: 57

Benefits of MVVM The ViewModel is an excellent place to put your validation logic for user input, view presentation logic, network requests. As a result, the ViewController files become far less bloated. Also, the View-ViewController component is completely isolated from the model. So during development, one developer can work on the UI part of the screen and another can take care of the logic for the screen, independently and concurrently. It is easy to redesign the UI without messing with the model logic since they are both completely isolated. As long as you link appropriate properties to the ViewModel, you can swap view components in and out. This gives more freedom to experiment with the UI. For Universal apps, both iPad and iPhone ViewControllers can interact with the same ViewModel. It’s easier to test. Developers can create unit tests for ViewModel and model without the View.

Upvotes: 1

Eimantas
Eimantas

Reputation: 49344

ViewModel is supposed to be a different entity from architectural POV, not from code placement POV. Your approach to MVVM with extensions to model makes model know too much and violates SRP e.g. if model has some date attribute, view model would usually be used for formatting it using current locale. If Model is data storage it should only contain relevant data structures and no methods. If Model is a service (e.g. networking client) it should contain only relevant methods with minimal data transform (e.g. json to struct).

Also in my practice I sometimes have more than one VM to a single Model. If, say, I have a User model with firstName, lastName and email attributes, I may need fullName property for displaying it in a table row (implemented in UserCellViewModel), but all three properties when displaying user information in detailed view (implemented in UserDetailViewModel). With extensions to model, all four properties (fullName being implemented in extension) would be accessible in all contexts. Making controller consuming the ViewModel know as little as possible is a good thing (citation needed). This may be achieved in Objective-C where your extensions can have their own header/interface files, but you don't get this in Swift.

Upvotes: 1

Related Questions