Refactoring an MVVM iOS app into VIPER

Marchell
5 min readJan 22, 2023
Photo by Kevin Ku on Unsplash

As some of you may know, last year I had the chance to participate in a coding challenge for a job vacancy. I developed an image grouping app based on a scanned QR code. I used the MVVM design pattern to implement it. While I’m aware it was not perfect, I still had a great time making the app since I learned quite a lot from it.

After I finished the app, I thought why not refactor it into the VIPER design pattern? VIPER has been very interesting for me because it’s very unique and complicated (at least for me). So learning it might be a challenge for me but I did it anyways. So let’s get to it, shall we?

What is VIPER?

VIPER is a design pattern for developing iOS apps. It is a backronym for View, Interactor, Presenter, Entity, and Router. It’s based on Single Responsibility Principle which leads to a clean architecture. I recommend reading this story if you want to know more about it since it explained it very well regarding the pattern.

The existing application

The current application I made uses the MVVM pattern. While it works fine, I feel like it’s still a bit messy. In this story, I’m gonna tell you how I refactor it into VIPER. And since it has a few features, I’m not gonna cover all of them. I’m gonna focus on the Data List feature. Right now it consists of 2 files, DataListVC.swift and DataListVM.swift.

DataListVC.swift

In the view controller, it’s mostly just setting up the UI and handle button taps. I also call the getAllData() method from the view model in viewWillAppear so every time I add new data, the list will automatically refresh itself to show the newly inputted data.

DataListVM.swift

The view model on the other hand performs quite a bit of operation. It retrieves the data from the CoreData model and the view controller will update the table view based on the retrieved data. It also performs navigation operations like showing some UIAlertControllers, and also pushing to a new page to add data and show the existing data.

Refactor it into VIPER

The VIPER pattern consists View, Interactor, Presenter, Entity, and Router. Since currently I only divide each feature into View Controller and View Model, I’m gonna divide the View Model’s responsibility into a few responsibilities. This feature will consists of a few more files like this diagram (based on this StackOverflow post):

  • View: This will send actions to the presenter and receive data updates from the presenter
  • Interactor: This will perform business logic. In this case, it will perform CRUD operations from the CoreData model like retrieving, adding, and deleting data.
  • Presenter: Acts like a middleman of the whole thing. Its responsibility is to ask the Interactor to perform business logic and shows the result to the View. It also asks the router to perform navigation operations.
  • Entity: Basically just a fancy name for the Data model object.
  • Router: This will create the module and perform navigation operations like showing alerts and pushing to a different screen.

So in this case, the view model will be broken into several parts. The part that handles all the navigation logic will be the router layer, the part that handles all the business logic will be the interactor layer, and the part that presents the data to the view will be the presenter layer.

Bringing it all together

So now that we have an idea of how VIPER works, I’m gonna show you what I did to refactor the app into the VIPER pattern. First, I created a few protocols for each layer like this:

These protocols will act as the blueprint of each layer. So each layer that conforms to each protocol has to have these functions in order to perform the logics.

The Presenter

The presenter acts as the layer to connect each layer to the other, pretty much like a middleman. For example, the view asks the presenter to perform something like getting data from something like an external API or CoreData model. Then the interactor will perform it and notify the presenter that it has done its job. The presenter then will notify the view that the data has been retrieved or updated so that the view can update itself.

The Interactor

The interactor acts as the layer that performs all the business logic. In this case, retrieving and deleting data from the CoreData model. Notice that in line number 9 and 14, it calls a method to notify the presenter that the operation has been performed and gives the data needed for the presenter to perform its continuation operations.

Notice that the interactor has a weak reference to the presenter. This is for avoiding retain cycles because the presenter already has a strong reference to the interactor.

The Router

The router acts as the layer to perform navigation operations. In this case, we have some methods to present alerts and push to a different screen like add data screen and data detail screen. Notice that in each UIAlertAction closure handler I called some presenter methods like in line 34, 48, etc. This is for notifying the presenter that the user has selected something that the presenter needs to update, and the presenter will do the rest.

Also there’s a a method called createModule. This method is for creating the entire feature like the view, interactor, presenter, and router before the app shows it to the user.

I also set the presenter reference as a weak reference to avoid retain cycles.

The View

The view acts as layer that shows the contents to the user. In this case we have a table view of some data. The view will ask the presenter to retrieve the data so that it can show it to the table view. The presenter will then retrieve it and notify the view and the view will automatically updates the table view to show the retrieved data.

And that’s it! We refactored the app from using the MVVM pattern to VIPER. I hope y’all could learn something from this story. You could clone the full app here. If you have some questions please reach me on my LinkedIn page. Thank you all and have a great day!

My LinkedIn and Github page.

--

--

Marchell

Noob iOS developer trying to git gud. I write to learn.