iOS Design Patterns - Part 4: MVVM | Ray Wenderlich

In this video, you’ll learn about Model-View-ViewModel (MVVM) which you’ll use to further combat massive view controllers.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/3816-ios-design-patterns/lessons/4

A rule of thumb that I seen is that the viewModel should not import UIKit. Your code example would work as well if you would import Foundation instead. Thoughts?

Why? ;]

Of all the patterns covered in this series, I found MVVM is implemented the most differently from developer to developer… and that’s okay.

Personally, I have very few “never do this mantras” in development.

In my experience, there is usually not a “best” solution to most development problems… and trying to find “the best one” is often just a waste of time.

There are a lot of good solutions, however, and a lot of bad solutions too… The trick is knowing the difference. :]

How can you tell good from bad solutions?

When I’m not sure about whether or not a design pattern (or specific implementation thereof) is right for a problem, I run it through the SOLID principles and see if it breaks any that I’m uncomfortable about or anticipate will cause big problems later…

If you’re not familiar with SOLID, I highly recommend reading Clean Code: A Handbook of Agile Software Craftsmanship.

Honestly, without these guiding principles, I’d be pretty lost in development… and from my experience, most developers that don’t know them struggle a lot more in day to day development.

:]

Hi,

thank you for taking the time to answer me. I was thinking of this presentation: https://news.realm.io/news/slug-max-alexander-mvvm-rxswift/

I also read some other articles regarding this point. But I completely agree with what you said, everybody has their own thoughts on how things should be and sometimes you need to adapt solution to your own needs.

I enjoyed this video, but would also like to see a video where you dig deeper into this subject.

Thanks again for the video and your reply.

Hi,

If I reference the model from the viewModel inside the viewController, does that ruin the design pattern?

For Example:
titleLabel.text = viewModel.user.name // user is the model and its owned by the viewmodel

is this wrong?

Reserveration :smiley:

@jrg.developer please answer me :slight_smile: I really need to know as I am starting a project with this pattern “MVVM” & I need to know if this is a wrong way to implement it.

I wouldn’t worry about “ruining” the design pattern per se, but rather ask yourself, “What problem is this going to help me solve?”

In this video, I propose that MVVM can be used to help combat the “massive view controller” problem-- that is, view controllers growing to be huge given enough time. Many apps have this issue, especially if you don’t address it specifically.

If I was trying to solve this problem using MVVM in a new app, I wouldn’t want to be putting more code than necessary into the view controller. Especially any sort of “transformation” code for displaying a model, I’d definitely want that in the view model.

Regarding this specific example, this may be okay to do. That is, viewModel.user.name may be directly settable on a view. And perhaps, you don’t want the view model to directly know about the view-- you just want it to do transformations.

Personally, however, just in case user.name needs to be transformed later in the life of the app (for some future reason), I’d likely create a convenience property for viewModel.userName, so that the view controller doesn’t access the model directly.

You may have other properties on viewModel that do other transformations too, so you might use viewModel like this within your view controller:

public func viewDidLoad() {
  super.viewDidLoad()
  titleLabel.text = viewModel.userName  // convenience for viewModel.user.name
  fullNameLabel.text = viewModel.userFullName // transformed user.firstName + user.lastName string
  lastLoginLabel.text = viewModel.displayDate  // transformed lastLoginDate into a string
  // ... etc...
}

For further reference, here’s another article that shows MVVM similar to what I’m describing here:

http://rasic.info/from-mvc-to-mvvm-in-swift/

Again, however, don’t worry too much about having to conform to a strict implementation per se, but rather, worry about “what are you trying to solve using this pattern?”

Good luck. :]

Thank you, Joshua for your detailed reply. I have read the attached link. My only problem with this approach is that I feel that there is a duplication of data. If I make a request that returns for example a list of pets. for every pet there are tens of properties. In this case I will have to duplicate the properties once in the model and another in the viewmodel. In this case for example we will have two pet breed which is duplication of data. Please correct me if I am wrong. @jrg.developer

Somewhat unrelated: When you create your new “ProductViewModel.swift” file, Xcode’s ‘template for your new file’ panel has three icons I don’t see in my Xcode – Swift Model, SwiftTestCase and ObjcTestCase. Where are these from?

Oops, I meant to hide those during recording. ;]

These are custom templates that I use during unit testing purposes. I learned how do create these from Jon Reid’s blog post, which gives an example template you can download:

Jon includes a Makefile within the download, but if you inspect its contents, you’ll see it’s simply copying the template to the correct locations that Xcode looks for custom templates.

Again, the important thing is to think about the problem you’re trying to solve.

The main value that a view model provides is transforming “model” data into “view model” data. The common, go-to example is converting a Date into a String representation: this is a very appropriate “view model” conversion.

If you’ve thought about your app’s problem, and you decide that it’s “okay” to have your view controller access the model directly for some things and use the view model for other things, go for it!

MVVM is simply a tool you can use… whether or not it improves your app depends on how you use it.

Plan first and code second. :]

I have also read in discussion groups that it would be better to only import Foundation.

The rationale behind this is that if I need a UIKit element in my ViewModel, this piece of code probably belongs in the UIViewController. It sort of helps keep “clean” the ViewModel and force better distribution of responsibilities within the project.

Niiiiice class :]
So, if the main focus is to avoid the massive View Controller, should I always prefer the MVVM approach to the MCV one? Is there some situation it would be better having a MCV than a MVVM other then just how big the Controller is?
Also, you combine the MVC-N from the previous video with the MVVM right?

Thanks!!

@jrg.developer Do you have any feedback regarding this? Thank you - much appreciated! :]

One use case for MVVM is helping to combat the “massive view controller problem.” However, it’s definitely not the only way to mitigate this issue, and it’s also definitely not the only cause of this issue.

That is, “massive view controller” commonly arises from developers trying to follow the Model-View-Controller pattern, yet they run into situations where a class/object/type isn’t actually a “model,” “view,” or “controller,” and instead of using another pattern, they decide the logic should get lumped into the controller… hence, massive view controllers! ;]

In this series, we talk about two cases in particular that don’t fit into MVC well:

(1) Networking… MVC-N addresses this by making “Networking” it’s own thing.

(2) View-models… MVVM addresses this by making “View Models” their own thing.

So to answer your question, “should I always prefer MVVM over MVC?”

I personally would answer “no,” especially if the primary reason is to avoid massive view controller, as MVVM won’t necessarily fix massive view controller in and of itself.

Also, if you start with MVVM, and your use case doesn’t actually require it (or doesn’t benefit much from it), you may wind up writing code that is just a time waste on the project… definitely something to avoid! ;]

In general, I recommend this basic approach:

  • Start simple. Unless you strongly suspect or have use cases otherwise for why you should prefer MVVM (or another pattern) over MVC, use MVC. It’s a “good starting point” most of the time.

  • As your app’s needs change over time (which may be the “first day” you start said project or even months into it), your code should change with it. This includes the patterns you use: it’s perfectly okay to adopt new patterns, or stop using ones that don’t make sense anymore, as your app’s needs change.

To mitigate the risk of “major refactors” with code changes over time, unit and automation testing can definitely help you. And, we have an iOS video series about that too!

https://videos.raywenderlich.com/courses/57-beginning-ios-unit-and-ui-testing/lessons/1

This course is a little dated, but I’d still recommend it if you haven’t gone through it already.

It’s also in the process of being updated too by another awesome developer on the RW team. :]

Nice explanation.
I have two questions for you.

  1. I see lot of articles against using KVO to notify change from ViewModel to View. What is your take on this?
  2. How do you cascade a network layer error to the ViewController that hosts that table view?
    Assuming that the network call initiated by the ViewModel class.
    KVO notification triggered only when there is a change in the array.
    The array will not change if the network call fails.

@jrg.developer Can you please help with this when you get a chance? Thank you - much appreciated! :]

Thanks for the positive feedback. :]

Regarding KVO, let’s be honest: Apple’s implementation for KVO sucks. Reasoning:

  • You must subclass NSObject to use it

  • While #keyPath is an improvement over String keys, they’re still very ugly and fairly brittle.

  • Every KVO notification goes through a single method: observeValue(forKeyPath: ...). At best, developers will call several other methods to handle the KVO notifications from this one. At worst, developers will stick a ton of code in this method. Either way, it’s a pain to maintain…!

Instead of KVO, I personally prefer use an Observable/Reactive implementation.

Here’s a pretty good writeup that explains how “Observables” work:

https://colindrake.me/post/an-observable-pattern-implementation-in-swift/

Another alternative is to use a full-fledged react library, such as RXSwift.

Regarding, “Is it okay to have KVO/Observable for a View Model?”

If it works with your use case, and you determine it doesn’t break SOLID, go for it!

Design patterns are a starting point, not the final implementation. Use and adapt them appropriately to satisfy your app needs.

In the apps that I support, however, I tend to find that the Observables wind up on the model.

Why? The change has to come from somewhere, and in my apps’ cases, this is usually due to changes resulting from networking calls. Since networking doesn’t know about view models (although again, consider your own use cases), it makes sense for this to be on the models in my case.

Your mileage may vary. ;]

While I’m not strictly against the idea of View Models making networking calls, I personally don’t often (ever?) do this.

Instead, I actually utilize both controllers and view models in my apps.

Some developers say that “View Models” replace View Controllers nearly entirely, including networking.

Again, consider what you’re to accomplish in your app’s use case:

Does it make sense for the view model to be making networking calls? Would it be better to use MVC-N in combination with MVVM, and keep networking calls in the view controller?

If you do decide to keep networking calls in MVVM, you’ll have to answer this question yourself:

What happens if there’s errors?

If you’re onboard with using React/Observables, does it make sense to have an observable property for an error, which your controller binds against?

This is the type of methodology I’d use to approach this problem.

Not every app will solve the same problem the same way, and that’s okay.

Just make sure it makes sense for your use case and that you understand the repercussions.

Good luck!

A BIG THANK YOU, for taking time to reply in detail.
Much appreciated! Your explanation is very helpful.
I am adding a new module to a legacy ObjC application.
In this situation, I cannot make an architectural change like moving to MVVM focused implementation like Rx.

On a minimum, I wanted to move the tableview delegates and data source and rest of the network calls to a new class called ViewModel. This is done and it works too.
The only issue I have is, not having an option to call a method defined in ViewController from ViewModel class.

How bad is to have a weak reference to the View in ViewModel considering ViewController has already a weak reference to ViewModel?