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

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

Esteban Torres

May 27, 2016
Tweet

More Decks by Esteban Torres

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  9. What now?
    Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

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

    View Slide

  11. And some Models
    struct Hops {
    let uuid: String
    let name: String?
    let amount: Double
    }
    Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

  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

    View Slide

  13. Network layer
    Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

  14. Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  21. Brewbot to the rescue(?)!!!
    Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

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

    View Slide

  23. Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  29. Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

  30. Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

  31. Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

  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 {
    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

    View Slide

  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

    View Slide

  34. Rx Bindings
    Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

  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

    View Slide

  36. So… what did we do? !
    Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

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

    View Slide

  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

    View Slide

  39. Questions?
    Esteban Torres - @esttorhe, iOSCon, 2016

    View Slide

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

    View Slide