Declarative UIKit, MVVM, DI, Combine, PropertyWrappers — Part 2
Implementing MVVM
level: Intermediate
Some info, before we Start:
MVVM:
What Wiki tell us about MVVM:
Model–view–viewmodel (MVVM) is a software architectural pattern that facilitates the separation of the development of the graphical user interface (the view) — be it via a markup language or GUI code — from the development of the business logic or back-end logic (the model) so that the view is not dependent on any specific model platform. The viewmodel of MVVM is a value converter,[1] meaning the viewmodel is responsible for exposing (converting) the data objects from the model in such a way that objects are easily managed and presented. In this respect, the viewmodel is more model than view, and handles most if not all of the view’s display logic.[1] The viewmodel may implement a mediator pattern, organizing access to the back-end logic around the set of use cases supported by the view.
Diagram:
So let’s implement ViewModel inside our project:
I’ll create a new file and call it ImageViewModel.
I want to separate my ImageVIewModel abstraction into two streams — Input and Output
Then I need to think what functionality must be declared there in ViewModel.
Project Target — is to get image after clicking on button and show it on View.
TO DO List:
- method to ask View model to make URLRequest
- notify my View that image is loading
- notify my View that image was loaded successfully or loading was failed
- update ImageView with image on success
Before we start using Combine let’s implement data binding using closures, and then I will refactor this with Combine
After adding all things from my TO DO list, my ViewModel will be look like this:
Now i want to implement getting image via URLRequest, cause of this article is not about NetworkLayer, but also i don’t want to fetch image directly inside ViewModel, cause ViewModel shouldn’t know anything about DataLoading, so to save our time i’ll create a simple ImageFetcher, here is:
So now i can implement image loading inside ViewModel without any URLRequest, just using ImageFether, let’s look to our ViewModel after this:
Then i want to use my closures that in future will notifies our View about something did happened, so we need to call our closures inside fetchImage() method:
Next step is to add ViewModel to our View, and bind them, let’s define viewModel inside ImageViewController right after UIComponents:
Now we need to set relations between ImageViewController and ImageViewController, i’ll create method bindToViewModel and implement there all relations that I need, add this func right after viewDidLoad func, and don’t forget to call bindToViewModel inside viewDidLow before the setupUI():
After this i need to implement my views reaction on this updates:
TO DO List:
1. On inProgress i want to let users know that something is loading, so i need to add some loader, in previous article we added LoaderView package, and i want to use his functionality to add or remove Loader from screen depends of loading state, also i want to show what is going on on my label
2. On imageDataLoaded i need to set image to my ImageView
3. On onFailure i want to show user that something went wrong
Let’s implement:
First of all we need to import LoaderView to ImageViewController
add this line right after importing DeclarativeUIKit:
There inside LoaderView Package we have Extension for UIViewController with two methods showLoader() and hideLoader(), so we can use them to show our user that something is loading, let’s return to bindeToViewModel() methods and define there showing of LoaderView, also we need don’t forget that all this operations will be working with UI elements so we need to put them inside main thread. And with this i want to add updating of ImageView and reaction on failure:
Next step is to update our handleBtnAction() method and remove no needed downloadImage(), at this point our ImageViewController must be looks like:
Deal with it!
Let’s Build & Run our project to see what we’ve got:
As you can see everything works as expected!
Thank you for reading, hope you enjoy)
In the next part we will refactor viewModel with Combine!