Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MVVM

 MVVM

Saritasa team talk

Agapov Alex

August 18, 2017
Tweet

More Decks by Agapov Alex

Other Decks in Programming

Transcript

  1. 1. What is MVVM briefly 2. Why MVVM is better

    than current (Pros & Cons) 3. Best practices 4. Rx + MVVM 5. Demo
  2. 1. What is MVVM ViewController Model Module / Story ViewModel

    ViewController Model Module / Story ViewModel ViewController / View Model Module / Story ViewModel MVVM
  3. 1. What can be ViewModel // Object converted from JSON

    class Human { var firstName: String var lastName: String var birthdate: String } // Converts Human object into formatted View Model class HumanViewModel { // Some call it ViewData var fullName: String var ageInDays: Int var birthdateDayMonth: String } // UIKit reusable View class HumanListViewController { … } // UI-independent data layer class HumanListViewModel { var people = [HumanViewModel]() func fetchPeople() {} } Any view can use Model to show data. Usually model is a bunch of strings+numbers+booleans. ViewModel is formatted model, ready to appear in View. Any ViewController can have a ViewModel to move all data logic into ViewModel. Any View can use a ViewModel to show formatted data in cells. All formatting should go into ViewModel.
  4. + – 1. Won't help with navigation between modules (Router

    / Coordinator linked with MVVM/MVC can) 2. Doesn't handle API (Moya could help us here) 3. Many responsibilities (Network, Data logic, Presentataion logic) 1. Maintainable (Separates UI and data handling) 2. Testable (We can test data formatting/mapping without affecting UI components) 3. Reusable (We can use one VC / VM for different screens) 4. Easily convertible from MVC (Can be used as starting point to better architecture) Con’s Pro’s 2. Why we should use MVVM
  5. 3. Best practices // UIKit reusable View class HumanListViewController {

    var submitButton: UIButton @IBAction tapSubmit() { viewModel.fetchPeople() } } // UI-independent data layer class HumanListViewModel { var people = [HumanViewModel]() func fetchPeople() {} } MVVM: • Never reference the view controller • Do not import UIKit. Make it a different file • Do not reference anything from UIKit. Even buttons. • It should only be data, i.e., strings, structs, JSON
  6. 4. MVC -> MVVM // MVC class HumanListViewController { var

    people = [Human]() … { provider.request( .people ) .filterSuccessfulStatusCodes() .mapArray(of: Human.self) .catchError({ error in return Observable.empty() }) .subscribe(onNext: { array in people = array } } } // UIKit reusable View class HumanListViewController { … { viewModel.didUpdatePeople = { error: (Error?) in tableView.reloadData() // Uses viewModel.people } viewModel.reloadPeople() // Runs on ibaction/refresh control } } // UI-independent data layer class HumanListViewModel { var didUpdatePeople: (Error?) -> Void = { _ in } private(set) var people = [Human]() func reloadPeople() provider.request( .people ) .filterSuccessfulStatusCodes() .mapArray(of: Human.self) .subscribe(onNext: { array in people = array self.didUpdatePeople(nil) } .catchError { error in self.didUpdatePeople(error) } } }
  7. 4. Bindings // UIKit reusable View class HumanListViewController { …

    { refreshControl.rx.controlEvent( .valueChanged ) .bind(to: viewModel.reload) .disposed(by: disposeBag) } } // UI-independent data layer class HumanListViewModel { // Input var reload = PublishSubject<Void> // Output var people = Observable<[Human]> init() { people = reload.asObserver() .flatMap ({ provider.request( .people ) .filterSuccessfulStatusCodes() .mapArray(of: Human.self) .catchError { error in return Observable.empty() } }) .map({ HumanListViewModel($0) }) } } MVVM can be bound with RxSwift+RxCocoa ViewController send events to ViewModel.
 ViewController subscribes to output properties of ViewModel. ViewModel process inputs into outputs asynchronously.