Whether you are an experienced iOS developer or have just started your career, it is essential that you utilize several iOS architecture patterns in your projects. Most of the developers don’t understand the significance of architecture patterns and end up facing critical problems within a couple of weeks after starting a new project.
Along with development strategies, modules, and other aspects of project development, pre-planning architecture patterns will also help you maintain a proper separation of concerns throughout your development process.
So, in today’s blog post we’ll be sharing a list of commonly used iOS architecture patterns and how you can use them in your projects to improve app’s functionality and ease out the development process.
Note: The following architecture patterns are only applicable in iOS applications which makes the following blog-post beneficial to iOS developers only.
What are Architecture Patterns?
Before moving any further, let’s first understand what architecture patterns are and why exactly do you need them?
For a developer, having a reusable solution is the best way to save time and efforts. Architecture patterns refer to similar reusable architecture solutions which a developer can use to deal with commonly occurring architecture issues.
Using architecture patterns is considered a wise approach because it saves time and helps the developer to design optimized and reusable solutions. Furthermore, complex software designs are modularized into separated smaller modules such that each module handles a functionality of its own.
Commonly Used iOS Architecture Patterns
As far as the iOS app development is concerned, developers rely on the following five major architecture patterns to reduce modularized iOS solutions.
- Apple’s MVC
Each of the above architecture patterns has pros and cons of their own. Choosing the one that complements your project completely depends on the type and requirements of your project.
MVC (Model View Controller)
MVC was probably the first architecture pattern to implement separation of concern to a certain level. The pattern separates the source code into one of the three components, i.e., Model, View, Controller. Each component has a functionality of its own.
- Model – Model is the central unit of the entire MVC pattern which solely deals with the data handling. It consists of a set of different classes which are responsible for data manipulation, object modeling, and parsing. In the classic MVC pattern, the model has no relativity to the view or view controller and operates as an independent component.
- View – View handles the graphical representation of data, i.e., it is the display unit which provides the user with objects via which he/she interacts with the data. Text fields, labels, and buttons, for instance. Though view has a direct access to the model, it cannot change the state of the model. The view can only access the model in the reading mode which restricts it from manipulating the model.
- Controller – Controller acts as a mediator between the model and view, whose sole responsibility is to restrict the view from changing the state of the model. However, despite being a mediator, it is not responsible for data transfers between the model and the view. Neither does it holds the state of the view.
Like we mentioned earlier, MVC implements separation of concern to a certain level only which makes it the least preferred choice of developers. In this pattern, the view and the controller are hardly distinguishable, mainly because of the massiveness of the controller.
However, while building smaller projects, MVC may prove to be an efficient architecture pattern as its implementation is easy.
With an aim to implement classic MVC pattern into projects, Apple introduced its own MVC pattern with certain distinguishable factors. Unlike, traditional MVC pattern, Apple’s MVC restricts the View from having a direct access to the Model.
Rather, it forwards its events to the Controller. It’s the Controller’s job to make changes to the Model (if necessary) and process View’s request. Furthermore, the Controller is also responsible for updating the values of View once the request has been processed.
What separates Apple’s MVC from the traditional MVC is the better implementation of separation of concerns. Since the view has no direct access to the model, each component of the MVC model operates individually, providing easy navigation between modules and better scope for testing.
MVP (Model View Presenter)
Despite having certain advantages over Classic MVC pattern, Apple’s MVC still fails to maintain proper separation of concern, mainly because of the tight coupling between view and controller.
When it comes to iOS projects, having a huge number of modules, Apple’s MVC may not be your best companion. So, we look for an upgraded version of MVC with better implementation of separation of concerns; the MVP pattern.
MVP is quite similar to classic MVC. However, the controller is replaced by the Presenter which acts as the mediator between View and the model. Unlike controller in MVC, the Presenter holds the state of the view and handles all its events as well.
The View has no direct access to the Model and the other way around. Both the View and Model are completely unaware of each other’s existence. The presenter is the only component which interacts with both these components.
Below are the responsibilities of the Presenter in MVP pattern.
- Holds the state of the view.
- Makes alterations to the state of the view. (if necessary)
- Keeps track of View’s events.
- Owns the model and make alterations to Model’s state. (if necessary)
Since implementation, several versions of MVP have been introduced, each having a different interaction mechanism between the View and Pattern. The two of the commonly used versions of MVP are:
- SuperVision Controller.
- Passive View.
SuperVision Controller – The SuperVision Controller separates the Presenter into two parts, i.e., Controller and the View. When the user inputs any data, the Controller acts as a Presenter and handles all necessary logic operations. However, in the case of View/Model synchronization task, the View handles all the operations such as data binding.
Passive View – Passive View offers a much better interpretation of the general principle of MVP pattern. The view is made completely passive, which means it does not have any interaction with the model at all.
The Controller jumps in every time the View wants to make an alteration to the state of the model. The Passive View MVP pattern offers much better scope for testing as the dependency between the View and Model is minimal.
MVVM (Model View ViewModel)
MVVM utilizes the similar approach to the MVC pattern with the controller being replaced by the ViewModel. However, what separates MVVM from previous architecture patterns is its separation between View Controller and the Model.
Model – Model is different in MVVM pattern as apart from data it holds business logic and validation logic as well. Furthermore, the Model neither depends on the View or the ViewModel. Unlike MVC and MVP patterns, the Model does not know about the View or the ViewModel and performs its operations on its own.
View – View is responsible for the appearance of the user interface and provides an interactive UI via which user interacts with the app. The View does keep a reference of the ViewModel but cannot interact with it directly.
Rather, you’ll have to manually design an interface, which performs data binding operations, through which View will interact with the ViewModel. However, like previous architecture patterns, View is completely unaware of the Model and has no considerable interaction with it whatsoever.
ViewModel – The Controller is replaced by the ViewModel in MVVM pattern which performs following tasks.
- Keep the state of the View.
- Make changes to Model.
- Change View’s state using data binding operations only.
MVVM was designed with the sole purpose of minimizing the dependency among View and ViewModel. In MVVM, the View and ViewModel operate on their own and only interact with each other via data binding operations. Since the dependency is minimal, the separation of concern is maintained properly.
All the above architecture patterns utilize an MV(X) structure where ‘M’ and ‘V’ are Model and View, and (X) is replaced by either Presenter or Controller. However, when it comes to separating each component of MV(X) structure, it is quite hard to distinguish between the (X) and the View.
Furthermore, large-scale projects need to have a navigable interface otherwise you’ll face critical issues during testing. Every MV(X) architecture patterns restrict a smooth navigation between modules and therefore they are usually avoided while working on large-scale projects.
In order to overcome this issue, VIPER got introduced which had five different layers and a better separation of a concern than MV(X) patterns. VIPER expands to View, Interactor, Presenter, Entity, and Router, each component of the VIPER’s architecture. With five different layers, it becomes easy for the developer to separate the entire architecture into layers.
Here’s how each component of VIPER works.
View- Like MVP, View is responsible for forwarding user actions to the presenter which then performs further logic operations. Both the Presenter and the View interact with each other via higher-level classes such as UIVIew and UIViewController. Apart from the Presenter and View, no other component of the architecture can access these classes.
Interactor- Interactor acts as a mediator between the Model (Entity) and Presenter. Unlike previous MV(X) architecture patterns, the Presenter has no clue about the existence of Model. It can only access data stored in Model through Interactor. However, it’s Interactor’s job to ensure that Presenter cannot access object classes of the Model.
Presenter- As we mentioned earlier, the Presenter performs logic operations on user events forwarded by the View. It does communicate with other layers. However, it cannot transform the data at all. The only job of the Presenter is to perform business logic.
Entity- Entities only contain data objects. However, they do not contain methods for data processing as data processing is Interactor’s job. All your data objects will reside in the entities.
Router- Router handles an uninterrupted navigation among the above modules of the VIPER architecture pattern.
Since there are five different modules with a dedicated routing mechanism, a proper navigation is maintained in VIPER, which eases out the testing.
In the above list, every new architecture pattern has some leverage over the previous one. However, it does not mean, we can completely avoid MVC architecture and start utilizing VIPER in every project.
As we mentioned earlier, the architecture pattern completely depends on the type of your project. Small-scale projects can still be developed using MVC and MVVM, and designing them using VIPER may result in unnecessary over-engineering. However, if you are working on large-scale projects with hundreds of modules, you cannot rely on MV(X) architecture patterns.