It's been a more than a year I am working with SwiftUI professionally. From very starting phase of app me and my time followed MMVM like Bible into the code base and today I want to share the road block we hit every time when we were enforcing MVVM with SwiftUI.
Road blocks with MVVM
Lets considered a scenario, where View contains ViewModel and ViewModel init contains Model.
In such case whenever you will init the View you need to pass Model to its ViewModel init. This seems pretty simple in normal use case but imagine some complex UI where we have a MainView with multiple sub views and each sub view will be calling the api to present the data and the sub views will only call the api once we get the data from MainView api.
So basically there are functional dependencies on Views or we can say that all view somewhat correlated in terms of presenting their content.
Let's dive into some real scenario to understand this in more crystal clear format.
This is how it will look like when you enforce the MVVM.
The problem with this system is managing all the view using single ViewModel and that to holding the model object for all those subViews.
I am not saying this will not work but it will put extra boiler plate code to manage view and their state.
Inspite of forcing the technology to follow certain patterns which we have in our knowledge base or what we are practising from long time we should understand the framework and its demand.
SwiftUI demands are something different and also offer one extra stuff to developer which is EnvironmentVariables , don't confuse this with Singleton classes. And the limitation of this is that it is not accessible in ViewModels which itself tell us something about SwiftUI framework.
We need to understand or think a little before even starting to code a screen . Below are few key points which I think we should considered before coding.
- Figure out the Views dependencies , might be functional or api level dependencies.
- Figure out the requirement of ViewModel , do not completely avoid it else Views will be loaded with lot of heavy lifting of UI and validation logic.
- Figure out the shared dependencies between views , and on basis of that create a single source of truth and inject that as environment variable dependency with ParentView.
- Flow like water , do not enforce your thoughts and ideas to framework.
For reference I am sharing one the GitHub project which follows the same pattern.
What will happen with Unit Test
As I mentioned , we should not enforce ViewModel which means we are not keeping like the way it is. There will be ViewModel as a UIValidator or Model data modifier or may be just holding the function which will take some input and return the data in a form what we require in View.
So there is still one class which will be doing some business logic and we can have the unit test cases for that.
Reference Article https://developer.apple.com/forums/thread/699003