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?
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âŠ
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.
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.
@jrg.developer please answer me 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:
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?â
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?
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.
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?
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!
I see lot of articles against using KVO to notify change from ViewModel to View. What is your take on this?
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.
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:
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.
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?