Implementing MVVM Binding with Swift Generics in iOS

Sean Lin
Cubo AI
Published in
5 min readApr 26, 2020

The MVVM Pattern

MVVM consists of three roles.

Model — In the model layer, we write our business logic

ViewModel- This layer basically interacts with view and model and provide observable object which is observed by the view.

View- the view is our view or controller. View observe the view model observable property to update its element.

The idea behind MVVM pattern is to utilize a view model handles the data for the view, which decreases the architecture complexity and keeps our view clean.

The default architecture pattern for building iOS applications is MVC (model view controller), and there is nothing wrong with the MVC pattern. But sometimes MVC is mixed responsibility, which leads to the “fat” view controller. And MVVM is a great pattern to prevent such problem.

Also, Apple introduce the BindableObject in SwiftUI and Combine framework, and it represents “An object that serves as a view’s model” . That’s exactly the concept of view models in MVVM.

Build an App with MVVM

To get a better understanding of MVVM, let us build a searching App with this architecture.

The main idea of this App is to search Apps in iTunes App Store by typing keywords. It is pretty simple, there is a search bar for users to input the searching text, and a list that shows all the searching results.

Before diving into the code, let’s talk about the concept of binding first.

What is binding🤔

Event Binding can tell the view that this function should be called whenever this event is triggered. In reactive binding, whenever the value is changed, the event binding will be triggered.

Here is a simple way to implement the binding behavior.
Bindable is a class that contains two properties: value and observer. We use Generics for the type of value. And the type of observer is a closure, which takes an input that is the same type of value.

And as you can see, whenever the value is set, the observer closure will be called.

We will use this bindable class to build our ViewModel later.

Model

Let us start with the Model. Result is the model that contains the all informations that for an App, like App name, App icon, user ratings, screenshots, and so on. The structure of Result is shown below.

ViewModel

Thanks to the bindable class, we are able to create the ViewModel that is responsible for notifying the View what kind of UI it should present.

Here is the ViewModel for the Apps Search View.

There are two bindable properties in the AppsSearchViewModel. One is the appResults, and another is isSearching.

appResults represents the searching results for the searching event. The value of appResults is an array of Result.

isSearching is a boolean that indicates user whether app is in the process of searching query currently.

And there is a function named as performSearch, it will execute the searching task with iTunes API.

When the searching task begins, we will change the value of isSearching into true. As soon as we get the searching results from iTunes API, we will pass the results to appResults and set a new value for it and also change the value of isSearching back to false.

View

In this project, we use a UICollectionViewController to be our View. And each cell in the UICollectionView represents each App in the searching results.

Inside the view, there is a searchViewModel which is the type of AppsSearchViewModel. The View doesn’t directly own the Model. All the things that the View needs to know is the ViewModel.

And for the collectionView delegation method, collectionView(_collectionView: UICollectionView, numberOfItemsInSection section: int), we just return the number of appResults in our searchViewModel directly.

c

Reactive Binding

Bindings between View and ViewModel is the main idea of MVVM architecture.

In the setupSearchViewModelObserver function, we use reactive programming to observe value changes.

In line 22–26, we observer the value change for appResults in searchViewModel and bind a closure on it. The closure is pretty simple, it will reload the collectionView in the main UI thread. Because appResults is a Bindable object, the binding closure will be called whenever its value is changed. In this way, when the appResults is updated, the collectionView will be updated automatically.

searchViewModel.appResults.bind { [weak self] (_) in                
DispatchQueue.main.async {
self?.collectionView.reloadData()
}
}

On the other hand, we also observer isSearching value changes in line 28–34. And inside the binding closure, we use isSearching value to determine whether the loading indicator should be hidden or not.

searchViewModel.isSearching.bind { [weak self] (isSearching) in              
guard let isSearching = isSearching else { return }
DispatchQueue.main.async {
isSearching ? self?.loadingIndicator.startAnimating() : self?.loadingIndicator.stopAnimating()
self?.loadingIndicator.isHidden = !isSearching
}
}

Event Handling

When user begins typing text in the search bar, we will receive the event from the searchBar delegate method func searchBar(_searchBar:UISearchBar, textDidChange searchText:String). And the only thing we need to do here is to trigger the searching method in our viewModel. That’s it, only one line code 🙌

You can find that we don’t write API codes in the view. We don’t need a completion closure to update UI after the searching is completed, either. As soon as the searching task is ended, the value of the observable viewModel will be changed. And due to the binding we implemented on the viewModel, the collectionView will be reloaded automatically and the loading indicator will also be shown/hidden properly.

Obviously, the code in the view is pretty simple and clean !!! 😎

Good job💪

You can check out the source code for it here.

Wrapping up

MVVM is an architecture pattern that is modeled after MVC but includes a separate View Model layer. This layer helps create a bridge for the Views to present information from Model objects. The main advantage of MVVM is to make the Views really slim and the controllers don’t become bloated.

In addition, Views are unaware of Models objects. Therefore, it is easy to present different object type in a View. This architecture pattern can be very powerful once you understand the implementation.

However, there are no silver bullets when it comes to building an iOS app architecture. Each one has its own drawbacks and may or may not suit your project. It depends on the case.

Hope this article is helpful to you!

Please don’t hesitate to leave any comments with your suggestions and ideas.

Thanks for reading! Happy coding ~ :D

--

--