iOS architecture patterns (MVC,MVVM,VIPER)

Image result for ios-architecture-patterns (MVC,MVVM,VIPER)In this blog we are going to discuss about iOS architecture design patterns.we have various options when it comes to architecture design patterns:

  • MVC
  • MVVM
  • VIPER

First, let’s start MVC pattern

Single_View_App_Template

Realistic Cocoa MVC

Cocoa MVC persuades you to write Massive View Controllers, since they are so concerned in View’s life cycle that it’s hard to state they are divided. While you still have ability to offload several of the business logic and data transformation to the Model, you don’t have much choice when it comes to offloading work to the View, each times all the responsibility of the View is to send actions to the Controller. The view controller ends up being a delegate and a data source of the whole thing, and is frequently responsible for dispatching and cancelling the network requests and… you name it.

var userCell = tableView.dequeueReusableCellWithIdentifier("identifier") as UserCell
userCell.configureWithUser(user)

The cell, which is the View organized directly with the Model, so MVC strategy are desecrated, but this occurs all the time, and generally people don’t feel it is wrong. If you strictly pursue the MVC, then you invented to configure the cell from the controller, and don’t pass the Model into the View, and this will raise the size of your Controller even more.

Cocoa MVC is logically unshortened as the Massive View Controller.

The problem may not be evident until it comes to the Unit Testing (hopefully, it does in your project). As your view controller is strongly coupled with the view, it becomes difficult to test because you have to be very creative in mocking views and their life cycle, whereas writing the view controller’s code in such a way, that your business logic is separated as much as possible from the view layout code.

Let’s have a appear on the simple playground example:

MVC example

import UIKit

struct Person { // Model
 let firstName: String
 let lastName: String
}

class GreetingViewController : UIViewController { // View + Controller
 var person: Person!
 let showGreetingButton = UIButton()
 let greetingLabel = UILabel()

 override func viewDidLoad() {
 super.viewDidLoad()
 self.showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside)
 }

 func didTapButton(button: UIButton) {
 let greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
 self.greetingLabel.text = greeting

 }
 // layout code goes here
}
// Assembling of MVC
let model = Person(firstName: "David", lastName: "Blaine")
let view = GreetingViewController()
view.person = model;

MVC assembling can be execute in the presenting view controllerMVC_Single_View_App_Template

This doesn’t seem very testable, right? We can move generation of greeting into the new GreetingModel class and test it separately, but we can’t test any presentation logic within the GreetingViewController without calling the UIView related methods directly (viewDidLoad, didTapButton) which may cause loading all views, and this is bad for the unit testing.

In detail, loading and testing UIViews on one simulator (e.g. iPhone 4S) doesn’t assurance that it would work fine on the other devices (e.g. iPad), so I’d suggest to remove “Host Application” from your Unit Test target configuration and run your tests without your application running on simulator.

The connections between the View and the Controller aren’t really testable with Unit Tests

With everyone said, it may appear that Cocoa MVC is a pretty bad pattern to desire. But let’s assess it in terms of features defined in the starting of the blog:

Distribution the View and the Model in fact divided, but the Viewand the Controller are tightly joined.

Testability — you’ll possibly only test your Model, due to the bad distribution.

Ease of use — the smallest amount of code among others patterns. In addition everyone is well-known with it, thus, it’s simply maintained even by the unexperienced developers.

Cocoa MVC is the outline of your choice if you are not set to use more time in your architecture, and you feel that something with higher protection cost is excess for your small project.

MVVM

The MVVM act the view controller as the View

There is no fixed combination between the View and the Model

Yet, this time not between the View and the Model, but between the View and the View Model.

Therefore what is the View Model in the iOS reality? It is essentially UIKit independent illustration of your View and its state. The View Model raise modifies in the Model and updates itself with the updated Model, and as we have a binding between the View and the View Model, the first is updated accordingly.

In our simple example, the FRF framework or even the KVO is overload, as a substitute we’ll openly ask the View Model to inform using showGreetingmethod and use the simple property for greetingDidChange callback function.

MVVM example

import UIKit

struct Person { // Model
 let firstName: String
 let lastName: String
}

protocol GreetingViewModelProtocol: class {
 var greeting: String? { get }
 var greetingDidChange: ((GreetingViewModelProtocol) -> ())? { get set } // function to call when greeting did change
 init(person: Person)
 func showGreeting()
}

class GreetingViewModel : GreetingViewModelProtocol {
 let person: Person
 var greeting: String? {
 didSet {
 self.greetingDidChange?(self)
 }
 }
 var greetingDidChange: ((GreetingViewModelProtocol) -> ())?
 required init(person: Person) {
 self.person = person
 }
 func showGreeting() {
 self.greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
 }
}

class GreetingViewController : UIViewController {
 var viewModel: GreetingViewModelProtocol! {
 didSet {
 self.viewModel.greetingDidChange = { [unowned self] viewModel in
 self.greetingLabel.text = viewModel.greeting
 }
 }
 }
 let showGreetingButton = UIButton()
 let greetingLabel = UILabel()

 override func viewDidLoad() {
 super.viewDidLoad()
 self.showGreetingButton.addTarget(self.viewModel, action: "showGreeting", forControlEvents: .TouchUpInside)
 }
 // layout code goes here
}
// Assembling of MVVM
let model = Person(firstName: "David", lastName: "Blaine")
let viewModel = GreetingViewModel(person: model)
let view = GreetingViewController()
view.viewModel = viewModel

Our feature appraisal:

Distribution — in our small example it is not clear, but, in fact, the MVVM’s View has more responsibilities than the MVP’s View. Because the first one updates it’s position from the View Model by setting up bindings, when the second one just forwards every events to the Presenter and doesn’t modernize itself.

Testability — the View Model identifing nothing about the View, this permits us to test it simply. The View may be also tested, but while it is UIKit dependant you may want to skip it.

Ease of use — in the actual app where you’d have to promote all events from the Viewto the Presenter and to update the View manually; MVVM would be much thinner if you used bindings.

The MVVM is very striking, since it joins advantages of the abovementioned approaches, and, in addition, it doesn’t need extra code for the View updates due to the bindings on the View side. however, testability is still on a fine level.

VIPER

LEGO building skills shifted into the iOS app design

VIPER is our end candidate, which is mostly interesting because it doesn’t come from the MV(X) category.

By now, you must concur that the grainy in responsibilities is very fine. VIPER creates an additional iteration on the idea of unscrambling responsibilities, and this time we have five layers.

VIPER

Interactor — encloses business logic related to the data or networking, like creating new instances of datas or fetching them from the server. For those reasons you’ll utilize some Services and Managers which are not measured as a part of VIPER module but rather an external addiction.

Presenter — encloses the UI related business logic, raises methods on the Interactor.

Entities — your basic data objects, not the data access layer, since that is a responsibility of the Interactor.

Router — liable for the segues between the VIPER modules.

Essentially, VIPER module can be a one screen or the whole user story of your application — imagine of authentication, which can be one screen or numerous connected ones. How tiny are your “LEGO” blocks? — It’s up to you.

If we evaluate it with the MV(X) kind, we’ll observe a few differences of the distribution of responsibilities:

Model logic moved into the Interactor with the Entities as dumb data structures.

Only the UI representation duties of the Controller/Presenter/ViewModel shifted into the Presenter, but not the data changing abilities.

VIPER is the first pattern which plainly addresses navigation liability, which is invented to be resolved by the Router.

Accurate way of doing routing is a challenge for the iOS applications, the MV(X) patterns basically don’t address this issue.

The example does not envelop routing or interaction between modules, as those topics are not covered by the MV(X) patterns at each one.

import UIKit

struct Person { // Entity (usually more complex e.g. NSManagedObject)
 let firstName: String
 let lastName: String
}

struct GreetingData { // Transport data structure (not Entity)
 let greeting: String
 let subject: String
}

protocol GreetingProvider {
 func provideGreetingData()
}

protocol GreetingOutput: class {
 func receiveGreetingData(greetingData: GreetingData)
}

class GreetingInteractor : GreetingProvider {
 weak var output: GreetingOutput!

 func provideGreetingData() {
 let person = Person(firstName: "David", lastName: "Blaine") // usually comes from data access layer
 let subject = person.firstName + " " + person.lastName
 let greeting = GreetingData(greeting: "Hello", subject: subject)
 self.output.receiveGreetingData(greeting)
 }
}

protocol GreetingViewEventHandler {
 func didTapShowGreetingButton()
}

protocol GreetingView: class {
 func setGreeting(greeting: String)
}

class GreetingPresenter : GreetingOutput, GreetingViewEventHandler {
 weak var view: GreetingView!
 var greetingProvider: GreetingProvider!

 func didTapShowGreetingButton() {
 self.greetingProvider.provideGreetingData()
 }

 func receiveGreetingData(greetingData: GreetingData) {
 let greeting = greetingData.greeting + " " + greetingData.subject
 self.view.setGreeting(greeting)
 }
}

class GreetingViewController : UIViewController, GreetingView {
 var eventHandler: GreetingViewEventHandler!
 let showGreetingButton = UIButton()
 let greetingLabel = UILabel()

override func viewDidLoad() {
 super.viewDidLoad()
 self.showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside)
 }

 func didTapButton(button: UIButton) {
 self.eventHandler.didTapShowGreetingButton()
 }

 func setGreeting(greeting: String) {
 self.greetingLabel.text = greeting
 }

 // layout code goes here
}
// Assembling of VIPER module, without Router
let view = GreetingViewController()
let presenter = GreetingPresenter()
let interactor = GreetingInteractor()
view.eventHandler = presenter
presenter.view = view
presenter.greetingProvider = interactor
interactor.output = presenter

Features:

Distribution — certainly, VIPER is a champion in distribution of responsibilities.

Testability —no disclosures here, better distribution and testability.

Ease of use — lastly, two above come in cost of maintainability as you already guessed. You cover to write vast amount of interface for classes with very tiny responsibilities.

In this blog we learned about the important iOS architecture design patterns, I hope this blog is useful to you.

Visit our ios App development Services.


Posted

in

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *