Guideline to choose best iOS Architecture Patterns
Demystifying MVC, MVP, MVVM and VIPER or any other design patterns to choose the best approach to building an app
MVP Patterns
Section titled “MVP Patterns”import UIKit
struct Person { // Model let firstName: String let lastName: String}
protocol GreetingView: class { func setGreeting(greeting: String)}
protocol GreetingViewPresenter { init(view: GreetingView, person: Person) func showGreeting()}
class GreetingPresenter : GreetingViewPresenter { unowned let view: GreetingView let person: Person required init(view: GreetingView, person: Person) { self.view = view self.person = person } func showGreeting() { let greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName self.view.setGreeting(greeting) }}
class GreetingViewController : UIViewController, GreetingView { var presenter: GreetingViewPresenter! let showGreetingButton = UIButton() let greetingLabel = UILabel()
override func viewDidLoad() { super.viewDidLoad() self.showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside) }
func didTapButton(button: UIButton) { self.presenter.showGreeting() }
func setGreeting(greeting: String) { self.greetingLabel.text = greeting }
// layout code goes here}// Assembling of MVPlet model = Person(firstName: "David", lastName: "Blaine")let view = GreetingViewController()let presenter = GreetingPresenter(view: view, person: model)view.presenter = presenterMVVM Pattern
Section titled “MVVM Pattern”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 MVVMlet model = Person(firstName: "David", lastName: "Blaine")let viewModel = GreetingViewModel(person: model)let view = GreetingViewController()view.viewModel = viewModelVIPER Pattern
Section titled “VIPER Pattern”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 Routerlet view = GreetingViewController()let presenter = GreetingPresenter()let interactor = GreetingInteractor()view.eventHandler = presenterpresenter.view = viewpresenter.greetingProvider = interactorinteractor.output = presenterMVC pattern
Section titled “MVC pattern”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 MVClet model = Person(firstName: "David", lastName: "Blaine")let view = GreetingViewController()view.person = model