MVVM + RxSwift + DataControllers

MVVM + RxSwift + DataControllers

Talk given at iOScon 2016 (https://skillsmatter.com/skillscasts/7863-mvvm-rxswift-and-datacontrollers).

How we at Brewbot.io tackled the missing «Data management» on MVVM and glued everything together with RxSwift

F2f5f7bc8bd3bd71e51d303e9881fe78?s=128

Esteban Torres

May 27, 2016
Tweet

Transcript

  1. MVVM, RxSwift and DataControllers Esteban Torres - @esttorhe, iOSCon, 2016

  2. MVC Esteban Torres - @esttorhe, iOSCon, 2016

  3. The «Problem» of MVC Esteban Torres - @esttorhe, iOSCon, 2016

  4. MVVM Esteban Torres - @esttorhe, iOSCon, 2016

  5. Model Esteban Torres - @esttorhe, iOSCon, 2016

  6. View Esteban Torres - @esttorhe, iOSCon, 2016

  7. ViewModel Esteban Torres - @esttorhe, iOSCon, 2016

  8. class MyViewModel { // The model being «formatted» private var

    model: MyModel? = nil // A formatted property let amountDueText: String { var currencyFormatter = NSNumberFormatter() currencyFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle currencyFormatter.locale = NSLocale.currentLocale() return currencyFormatter.stringFromNumber(model?.amount) ?? 0) } } Esteban Torres - @esttorhe, iOSCon, 2016
  9. What now? Esteban Torres - @esttorhe, iOSCon, 2016

  10. Let's make some UI Esteban Torres - @esttorhe, iOSCon, 2016

  11. And some Models struct Hops { let uuid: String let

    name: String? let amount: Double } Esteban Torres - @esttorhe, iOSCon, 2016
  12. Enter ViewModels class HopsViewModel { // Model private let model:

    Hops // Properties var name: String { return model.name ?? "N/A" } var amount: String { // Notice how here we should convert to the user's unit (imperial / metric) return "\(model.amount) g" } init(withHop hop: Hop) … } Esteban Torres - @esttorhe, iOSCon, 2016
  13. Network layer Esteban Torres - @esttorhe, iOSCon, 2016

  14. Esteban Torres - @esttorhe, iOSCon, 2016

  15. !❓ Esteban Torres - @esttorhe, iOSCon, 2016

  16. ! Esteban Torres - @esttorhe, iOSCon, 2016

  17. ! Esteban Torres - @esttorhe, iOSCon, 2016

  18. class ViewModelA { private let model: Model var formattedCurrency: String…

    var formattedProperty1: Double… var formattedProperty2: String… … … init(withModel model: Model) … func getModels(closure:([Model]) -> ()) -> Void { API.request(.GetModels) { jsonResponse in // Parse the JSON response here let models = … closure(models) } } } Esteban Torres - @esttorhe, iOSCon, 2016
  19. ! Esteban Torres - @esttorhe, iOSCon, 2016

  20. MVVM …an abstraction of the view exposing public properties and

    commands… In the view model, the binder mediates communication between the view and the data binder. The view model has been described as a state of the data in the model.1 1 http://wayback.archive.org/web/20080201101909/http://www.acceptedeclectic.com/2008/01/model-view-viewmodel- pattern-for-wpf.html Esteban Torres - @esttorhe, iOSCon, 2016
  21. Brewbot to the rescue(?)!!! Esteban Torres - @esttorhe, iOSCon, 2016

  22. DataControllers Esteban Torres - @esttorhe, iOSCon, 2016

  23. Esteban Torres - @esttorhe, iOSCon, 2016

  24. But there's more… Esteban Torres - @esttorhe, iOSCon, 2016

  25. The age of Swift Esteban Torres - @esttorhe, iOSCon, 2016

  26. MVVM + RxSwift + DataControllers Esteban Torres - @esttorhe, iOSCon,

    2016
  27. RxSwift Esteban Torres - @esttorhe, iOSCon, 2016

  28. ! Esteban Torres - @esttorhe, iOSCon, 2016

  29. Esteban Torres - @esttorhe, iOSCon, 2016

  30. Esteban Torres - @esttorhe, iOSCon, 2016

  31. Esteban Torres - @esttorhe, iOSCon, 2016

  32. class ViewModel { // Hold a reference to our DataController

    private let dataController: DataController // Hold a reference to the model we will be getting private var model: Model? func getModel(id: Int) -> Observable<Model> { return Observable.create { observer in dataController.getModel(id) .subscribe(onNext: { [unowned self] model in self.model = model // If we need to format something else we should do it here observer.onNext(self.model) }, onError: { error in // Maybe properly format the error to the user here as well observer.onError(error) } ).addDisposableTo(disposeBag) } } } Esteban Torres - @esttorhe, iOSCon, 2016
  33. class ViewController: UIViewController { // Retain a reference to our

    ViewModel private let viewModel: ViewModel func loadData() -> Void { self.viewModel.loadModel() .subscribeOn(MainScheduler.instance) .subscribe(onNext: { [unonwed self] viewModel in // Update your `UI` accordingly self.nameLabel.text = viewModel.formattedName self.amountLabel.tet = viewModel.hopsAmount }, onError: { error in } }) .addDisposableTo(disposeBag) } } Esteban Torres - @esttorhe, iOSCon, 2016
  34. Rx Bindings Esteban Torres - @esttorhe, iOSCon, 2016

  35. class ViewController: UIViewController { // Retain a reference to our

    ViewModel private let viewModel: ViewModel // Binding function override func viewDidLoad() { super.viewDidLoad() self.bindComponents() } } private extension ViewController { func bindComponents() -> Void { self.viewModel .formattedName .bindTo(self.nameLabel.rx_text) .addDisposableTo(disposeBag) self.viewModel .hopsAmount .bindTo(self.amountLabel.rx_text) .addDisposableTo(disposeBag) } } Esteban Torres - @esttorhe, iOSCon, 2016
  36. So… what did we do? ! Esteban Torres - @esttorhe,

    iOSCon, 2016
  37. Conclusion Esteban Torres - @esttorhe, iOSCon, 2016

  38. . "That was the worst idea EVER… BUT seeing how

    badly they tackled that problem gave me an idea about how to actually make it work." Esteban Torres - @esttorhe, iOSCon, 2016
  39. Questions? Esteban Torres - @esttorhe, iOSCon, 2016

  40. Thanks Esteban Torres - @esttorhe, iOSCon, 2016