The Model-View-Controller is a common design pattern when it comes to the development of an iOS application. Usually the view layer consists of elements from UIKit defined programmatically or in xib-files, the model layer contains the business logic of the application and the controller layer, represented by classes of UIViewController, is the glue between model and view.

The MVC pattern
One good part of this pattern is to have the business logic and business rules encapsulated in the model layer.However, the UIViewController still contains the UI related logic which means things like:
- calling the business logic and bind the results to the view
- managing the view elements
- transforming the data coming from the model layer into a UI friendly format
- navigation logic
- managing the UI state
- and more …
Having all of those responsibilities, ViewControllers often get huge and hard to maintain and to test.
So, it is time to think about improving MVC to deal with those problems. Let’s call this improvement Model-View-Presenter MVP.
The MVP pattern was first introduced in 1996 by Mike Potel and was discussed several times over the years. In his article GUI Architectures Martin Fowler discussed this pattern and compared it with other patterns for managing UI code.
There are many variations of MVP with small differences between them. In this post, i chose the common one that seems to be mostly used in the today’s app development. The characteristics of this variant are:
- the view part of the MVP consists of both UIViews and UIViewController
- the view delegates user interactions to the presenter
- the presenter contains the logic to handle user interactions
- the presenter communicates with model layer, converts the data to UI friendly format, and updates the view
- the presenter has no dependencies to UIKit
- the view is passiv (dump)

The MVP pattern
The following example will show you how to use MVP in action.
Our example is a very simple application, that displays a simple user list. You can get the complete source code from hier: https://github.com/iyadagha/iOS-mvp-sample .
Let’s start with a simple data model for the user:
struct User { let firstName: String let lastName: String let email: String let age: Int }
Then we implement a simple UserService, that asynchronously returns a list of users:
class UserService { //the service delivers mocked data with a delay func getUsers(callBack:([User]) -> Void){ let users = [User(firstName: "Iyad", lastName: "Agha", email: "iyad@test.com", age: 36), User(firstName: "Mila", lastName: "Haward", email: "mila@test.com", age: 24), User(firstName: "Mark", lastName: "Astun", email: "mark@test.com", age: 39) ] let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC))) dispatch_after(delayTime, dispatch_get_main_queue()) { callBack(users) } } }
The next step ist writing the UserPresenter. First we need a data model of the user, that can be directly used from the view. It contains properly formatted data as needed from the view:
struct UserViewData{ let name: String let age: String }
After that, we need an abstraction of the view, which can be used in the presenter without knowing about UIViewController. We do that by defining a protocol UserView:
protocol UserView: NSObjectProtocol { func startLoading() func finishLoading() func setUsers(users: [UserViewData]) func setEmptyUsers() }
This protocol will be used in the presenter and will be implemented later from the UIViewController. Basically, the protocol contains functions called in the presenter to control the view.
The presenter itself looks like:
class UserPresenter { private let userService:UserService weak private var userView : UserView? init(userService:UserService){ self.userService = userService } func attachView(view:UserView){ userView = view } func detachView() { userView = nil } func getUsers(){ self.userView?.startLoading() userService.getUsers{ [weak self] users in self?.userView?.finishLoading() if(users.count == 0){ self?.userView?.setEmptyUsers() }else{ let mappedUsers = users.map{ return UserViewData(name: "\($0.firstName) \($0.lastName)", age: "\($0.age) years") } self?.userView?.setUsers(mappedUsers) } } } }
The presenter hat the functions attachView(view:UserView)
and attachView(view:UserView)
to have more control in the UIViewContoller’s life cycle method as we will see later.
Note that converting User
to UserViewData
is a responsibility of the presenter. Also note that userView
must be weak to avoid retain cycle.
The last part of the implementation is the UserViewController:
class UserViewController: UIViewController { @IBOutlet weak var emptyView: UIView? @IBOutlet weak var tableView: UITableView? @IBOutlet weak var activityIndicator: UIActivityIndicatorView? private let userPresenter = UserPresenter(userService: UserService()) private var usersToDisplay = [UserViewData]() override func viewDidLoad() { super.viewDidLoad() tableView?.dataSource = self activityIndicator?.hidesWhenStopped = true userPresenter.attachView(self) userPresenter.getUsers() } }
Our ViewController has a tableView to display the user list, an emptyView to display, if no users are available and an activityIndicator to display while the app is loading users. Furthermore, it has a userPresenter and a list of users.
In the viewDidLoad
method, the UserViewController attach itself to the presenter. This works because the UserViewController, as we will see soon, implements the UserView protocol.
extension UserViewController: UserView { func startLoading() { activityIndicator?.startAnimating() } func finishLoading() { activityIndicator?.stopAnimating() } func setUsers(users: [UserViewData]) { usersToDisplay = users tableView?.hidden = false emptyView?.hidden = true; tableView?.reloadData() } func setEmptyUsers() { tableView?.hidden = true emptyView?.hidden = false; } }
As we see, these functions contains no complex logic, they are just doing pure view management.
Finally, the UITableViewDataSource
implementation is very basic and looks like:
extension UserViewController: UITableViewDataSource { func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return usersToDisplay.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "UserCell") let userViewData = usersToDisplay[indexPath.row] cell.textLabel?.text = userViewData.name cell.detailTextLabel?.text = userViewData.age cell.textLabel return cell } }

The end result yeah
Unit testing
One of the benefits of doing MVP is to be able to test the biggest part of the UI logic without testing the UIViewController itself. So if we have a good unit test coverage of our presenter, we don’t need to write unit tests for the UIViewController anymore.
Let’s now have a look on how we can test our UserPresenter. First we define tow mocks to work with. One mock is of the UserService to make it deliver the needed list of users. The other mock is of the UserView to verify if the methods are called properly.
class UserServiceMock: UserService { private let users: [User] init(users: [User]) { self.users = users } override func getUsers(callBack: ([User]) -> Void) { callBack(users) } } class UserViewMock : NSObject, UserView{ var setUsersCalled = false var setEmptyUsersCalled = false func setUsers(users: [UserViewData]) { setUsersCalled = true } func setEmptyUsers() { setEmptyUsersCalled = true } }
Now, we can test if the presenter behave correctly when the service delivers a non empty list of users.
class UserPresenterTest: XCTestCase { let emptyUsersServiceMock = UserServiceMock(users:[User]()) let towUsersServiceMock = UserServiceMock(users:[User(firstName: "firstname1", lastName: "lastname1", email: "first@test.com", age: 30), User(firstName: "firstname2", lastName: "lastname2", email: "second@test.com", age: 24)]) func testShouldSetUsers() { //given let userViewMock = UserViewMock() let userPresenterUnderTest = UserPresenter(userService: towUsersServiceMock) userPresenterUnderTest.attachView(userViewMock) //when userPresenterUnderTest.getUsers() //verify XCTAssertTrue(userViewMock.setUsersCalled) } }
In the same way we can test if the presenter works correctly if the service returns an empty list of users.
func testShouldSetEmptyIfNoUserAvailable() { //given let userViewMock = UserViewMock() let userPresenterUnderTest = UserPresenter(userService: emptyUsersServiceMock) userPresenterUnderTest.attachView(userViewMock) //when userPresenterUnderTest.getUsers() //verify XCTAssertTrue(userViewMock.setEmptyUsersCalled) }
Where to go from there
We have seen that MVP is an evolution of MVC. We only need to put the UI logic in an extra component called presenter and make our UIViewController passiv (dump).
One of the characteristics of MVP ist that both presenter and view know each other. The view, in this case the UIViewController, have a reference of the presenter and vice versa.
Though the reference of the view used in presenter could be removed using reactive programing. With reactive frameworks such as ReactiveCocoa or RxSwift it is possible to build an architecture, where only the view knows about the presenter and not vice versa. In this case the architecture would be called MVVM.
If you like to learn more about MVVM in iOS please check the following posts:
MVVM Tutorial with ReactiveCocoa
Implementing MVVM in iOS with RxSwift
What does “passiv (dump)” mean?
Hi Dave,
this means that the UIViewController does not understand what it is doing. It only does what the presenter tell it.
Basically the UIViewController is controlled by the presenter
Don’t you think that UserViewData is a duplication of the model.
We can consider it as a model. is it ok to use it inside the controller ??
Hi Saad,
yes, you can see it as a copy of the model which is optimised for presentation. The idea here is to keep the data preparation outside the UIViewController to keep it as small as possible.
Having read this I believed it was very enlightening. I appreciate you finding the time and effort to put this information together. I once again find myself personally spending a lot of time both reading and commenting. But so what, it was still worth it!|
Before reading this article I understood the difference between MVP and MVC, but I couldn’t see the advantage because I was unsure where precisely the responsibility lay for updating components on the UIView. The most common examples of MVP use a UITableView for their example and pass a UITableViewCell to the presenter for updating. This did not appear to be a real improvement to me, just shifting the code around.
However, your example included the line “The presenter has no dependencies to UIKit.”. This is probably the most important line of the whole tutorial. It strongly clarifies the different responsibilities of the Presenter and the UIViewController. The presenter presents data in a view agnostic manner. If the application were to be ported from iOS to macOS, modifications to the Presenter should not be needed.
Thanks for that clarification.
One question:
How do you do unit test for View Controller?
In our team we are using Snapshot tests using https://github.com/facebook/ios-snapshot-test-case and UITests using https://github.com/google/EarlGrey
Both are kind of blackbox testing technologies which help you to guarantee that your UIViewControllers are working as intended
Hi! When do you use detach view? You never used it in your example.
Hi,
since the presenter has only a weak reference of the View you do not need to call it explicitly. But for clarity reasons i would call it. A good place for it is the dealloc method of the UIViewController
I have 2 questions:
1. What about the navigation, who is the responsable?
2. Is this similar to MVVM? I found the Presenter == ViewModel, because the VM has these things:
– UI state
– Services
– Model
– Testable, we can test the ui through VM(this contains the state of the UI).
Regards.
Thanks Eli for your good questions.
1. The pure MVP does not say anything explicitly about the navigation logic. Applying the principles of MVP to navigations means that the presenter should manage the navigation and the view should execute it. There is a different pattern called VIPER which contains a routing component responsible for the navigation.
2. The MVVM is also a good pattern which addresses a different problem. The main responsibility of the VM is to calculate and prepare the data for the view. The view logic for example when to show an empty screen or when to show an error message remains in the view itself. Using MVP the whole UI related logic is part of a testable presenter.
Thanks for this nice walkthrough. I have really enjoyed it.
I’m also keen on VIPER approach. It brings even more testablitily, but add more boilerplate code. So, question myself if MVP is better answer.
Check this out: https://medium.com/brigade-engineering/brigades-experience-using-an-mvc-alternative-36ef1601a41f#.x29be74ne
Thank you Oleg for your comment.I consider the MVP as the simplest way to make the UIViewController have less logic. I already read the article ritten by Ryan about VIPER. My problem with this and also with Uncle’ Bob clean architecture is that they seems to me a bit overengineered, and as you said, in a real world app you would produce a lot of boilerplate.
Yepp, it’s a double-edged question. And my current feel on VIPER is exact feel of overengineering :/ Especially if you have a nice Services & DI already