Understanding the Transition from MVC to MVVM in iOS Projects
Hey folks! We’re going to do something different today. I wrote an article about MVC Design Pattern before and I added a sample project to the article. Today we’re going to look at how we migrate a project from MVC to MVVM.
You can check out the article I talked about MVC here.
We know that MVC has some shortcomings. You may even have heard that most people complain about MVC. (I don’t think anyone can deny that MVC is too easy for a newbie.) So why are people complaining? We write all the code to the controllers and the model layer accesses it directly. This complicates both code tracking and testability. It’s not a pleasant situation. Did you experience this? I usually do this, lol.
To summarize, MVC isn’t bad, but it’s not good either. Considering a controller that can find hundreds of rows depending on the project size, you might think it’s not good either. At this point, we will concentrate on another architecture.
So what is this MVVM?
Model-View-View Model, in short MVVM, is an architecture used instead of MVC and introduces us to a new layer. This is a View Model. The View Model is responsible for managing the Model. We can pass the data in the Model to the controllers through this layer. So it acts as middleware.
So how do we figure out what’s where? Let’s think simple.
The Model layer is where we keep our data and represents the business logic. The Model layer is unaware of any other layer.
The View Model layer processes the data it receives from the Model layer. It transforms the received data and is responsible for managing them. Also, the presentation logic is located here. As in the image above, View Model and Model are in conversation. This is achieved with data binding. The View Model knows the Model layer but not the View layer.
The View layer is the face of our application that the user sees. In short, it is the place where we show the data to the user. View knows View Model but cannot access Model directly. In this case, the Storyboard, Cell, and View Controllers are inside the View layer.
Now let’s try using MVVM and convert a project written in MVC to MVVM step by step.
For refactoring, we will reference an app that I wrote with MVC. This app is a simple news app. We are getting important news headlines daily from an API.
You can find the entire project here.
Now we will talk about how to go from MVC to MVVM. 🚀
When you clone the project to your computer and run it, you will see something like this:
There are three groups in the directory: Model, View, and Controller. In addition to these, we also have a Service group to which we send a network request. Since I have mentioned Model, View, and Controller in detail in the MVC article, I will not talk about what they are here. I’m just assuming we know these.
Before we start refactoring, let’s open a View Model group in the project directory. We’ll start with the Controller part because it’s the most crowded place for now. This will be the first point we will focus on.
Let’s start with the ArticleViewController, and try to understand what’s going on here.
This piece of code is the view controller before the extension was added. We are using a table view as an IBOutlet. This is the UI element that we will display the data we have taken on the screen. We use the variables articles and selectIndex as private variables, the articles array represents the array that we will throw the data we get from the API. We’re going to talk about the SelectIndex variable a little bit, We're skipping it for now.
Looking inside viewDidLoad() we see a setup() function.
This setup() function contains the binding process of the tableView and the function where we fetch the data we request.
Now let’s look at the fetchData() function.
This function sends a request to the network using the web service we wrote and throws the data into the empty array we created. Then, we load the data to the UI using the reloadTableView() function.
We can’t always get a response due to a problem with the API. That’s why I wrote an alert function. You will see this on the screen when it stays in the loading state. If you download the source code of the app, you can examine it from there.
Now let’s take a look at the extension part. (Are you aware this is a really fat view controller?)
Inside the Extension, we see two functions. The task of our first function is to return the number of rows. The second function gives us the index of the article. Let’s continue.
Here we see the operations we have done for the tableView. And we can also see that we are transferring data to another ViewController. That’s what the ArticleViewController is all about. Now we will make some changes.
Creating ArticleListViewModel
Let’s start by creating a mechanism that will allow the ViewController to communicate with the ViewModel.
With the help of this, we will be able to listen to the process. Before we start creating the ViewModel, let’s go back to the ViewController and initialize the ViewModel here.
Then,
Okay, now we have access to ViewModel from Controller. Now we can start creating the ViewModel.
As we know, the ViewController should not have been aware of the Model in MVVM architecture. We will move the data of the Model in the Controller to the ViewModel.
Let’s write a function to listen to the ViewModel.
We will now be able to track using viewStateBlock.
If we remember the ViewController in the project written in MVC, the network request was located here. And it was very ugly. Now we will write the Network request here.
Although it looks the same, we will use viewStateBlock differently here. We will report the process as “loading” before the articles we get from the URL come to us. After we receive the articles, we will update the process as “done”. Cutie. 💖
Actually, it’s almost finished. Let’s go back to the controller. Now we’ll see what we can get from the extension.
Do you remember this thingy? We will write this part inside the ViewModel as it contains information about the model. The Controller will not have direct access to articles.
We have created the ViewModel. We’re done here. Now, let’s go back to the Controller.
You remember that we initialize the ViewModel in the Controller. And we wrote a function called callToViewModel(). Now we will write a new function. This function will use the listenViewModel() function.
This function will allow us to see “loading” text in the console if the process is in progress, if the process is “done”, we will load the data into the tableView.
What’s next now? Let’s make some changes to the setup() function in the previous version.
TableView related setup function will not be included here. Because I used TableViewController in the project written with MVVM.
Don’t forget to get fetchData() function from ViewModel. Because we make requests. We will also call this function inside viewDidLoad. We are slowly coming to the end.
Now let’s see what we can do in the extension. The functions here belong to the tableView, which means we are bound to the UI element. The only action we will do here will be to use the operations we carried from the previous version here through the ViewModel.
As you can see, we accessed everything I needed to access with the articleListVM we created at the very beginning.
Thus, we have finished the editing process in the Controller. I will not explain the operations for the DetailViewController in the project in detail because we will apply the same logic there as what we are doing here.
You can find the latest version of the project here.
As you code, you’ll find that MVVM is actually more enjoyable than MVC. Using MVVM will increase the quality of your code and make it easier to test. You can reach me on my social media accounts if you have any questions. Thank you for reading. I hope you enjoyed it. See you in the next article.