Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

MVC Esteban Torres - @esttorhe, iOSCon, 2016

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

MVVM Esteban Torres - @esttorhe, iOSCon, 2016

Slide 5

Slide 5 text

Model Esteban Torres - @esttorhe, iOSCon, 2016

Slide 6

Slide 6 text

View Esteban Torres - @esttorhe, iOSCon, 2016

Slide 7

Slide 7 text

ViewModel Esteban Torres - @esttorhe, iOSCon, 2016

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Network layer Esteban Torres - @esttorhe, iOSCon, 2016

Slide 14

Slide 14 text

Esteban Torres - @esttorhe, iOSCon, 2016

Slide 15

Slide 15 text

!❓ Esteban Torres - @esttorhe, iOSCon, 2016

Slide 16

Slide 16 text

! Esteban Torres - @esttorhe, iOSCon, 2016

Slide 17

Slide 17 text

! Esteban Torres - @esttorhe, iOSCon, 2016

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

! Esteban Torres - @esttorhe, iOSCon, 2016

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

DataControllers Esteban Torres - @esttorhe, iOSCon, 2016

Slide 23

Slide 23 text

Esteban Torres - @esttorhe, iOSCon, 2016

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

RxSwift Esteban Torres - @esttorhe, iOSCon, 2016

Slide 28

Slide 28 text

! Esteban Torres - @esttorhe, iOSCon, 2016

Slide 29

Slide 29 text

Esteban Torres - @esttorhe, iOSCon, 2016

Slide 30

Slide 30 text

Esteban Torres - @esttorhe, iOSCon, 2016

Slide 31

Slide 31 text

Esteban Torres - @esttorhe, iOSCon, 2016

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

Rx Bindings Esteban Torres - @esttorhe, iOSCon, 2016

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

Conclusion Esteban Torres - @esttorhe, iOSCon, 2016

Slide 38

Slide 38 text

. "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

Slide 39

Slide 39 text

Questions? Esteban Torres - @esttorhe, iOSCon, 2016

Slide 40

Slide 40 text

Thanks Esteban Torres - @esttorhe, iOSCon, 2016