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

Data driven view controllers

Data driven view controllers

Originally posted here: https://speakerdeck.com/vmalakhovskiy/data-driven-view-controllers

Github link: https://github.com/vmalakhovskiy/data-driven-vc

Vitaly about his workshop:
"I will show how to unify/simplify view-presenter communication, using data-driven approauch. Of cource a bit about functional programming, code generation, comparison with other architectures and more."

This workshop was made for CocoaHeads Kyiv #14 which took place Oct 6 2018.

CocoaHeads Ukraine

October 06, 2018
Tweet

More Decks by CocoaHeads Ukraine

Other Decks in Programming

Transcript

  1. data-driven
    view controllers
    Vitalii
    Malakhovskyi
    Vitalii Malakhovskyi, BetterMe 1

    View Slide

  2. Vitalii Malakhovskyi, BetterMe 2

    View Slide

  3. Plan
    » what is data driven view controllers?
    » basic examples
    » code
    » home work: github
    Vitalii Malakhovskyi, BetterMe 3

    View Slide

  4. what is that,
    data-driven view controllers?
    Vitalii Malakhovskyi, BetterMe 4

    View Slide

  5. simplest view data representation as
    possible
    Vitalii Malakhovskyi, BetterMe 5

    View Slide

  6. struct/enum
    immutable!
    Vitalii Malakhovskyi, BetterMe 6

    View Slide

  7. struct ViewData {
    let title: String
    let message: String
    }
    Vitalii Malakhovskyi, BetterMe 7

    View Slide

  8. Doesn't know about
    » entities
    » managed objects
    » models
    » services
    » etc
    Vitalii Malakhovskyi, BetterMe 8

    View Slide

  9. it's only about view
    Vitalii Malakhovskyi, BetterMe 9

    View Slide

  10. May contain:
    » string, number, bool
    » struct, enum, array
    » nested
    » closure <- for output
    Vitalii Malakhovskyi, BetterMe 10

    View Slide

  11. ()->()
    Vitalii Malakhovskyi, BetterMe 11

    View Slide

  12. (Input)->()
    Vitalii Malakhovskyi, BetterMe 12

    View Slide

  13. ((Input)->())?
    Vitalii Malakhovskyi, BetterMe 13

    View Slide

  14. (Input)->(Output)
    Vitalii Malakhovskyi, BetterMe 14

    View Slide

  15. (Input)-> throws ()
    Vitalii Malakhovskyi, BetterMe 15

    View Slide

  16. struct Props {
    let title: String
    let journeys: [ViewData.Journey]
    struct Journey {
    let name: String
    let description: String
    let image: UIImage
    let progress: String
    let isLocked: Bool
    let onSelect: () -> ()
    }
    }
    Vitalii Malakhovskyi, BetterMe 16

    View Slide

  17. struct Props {
    let title: String
    let journeys: [ViewData.Journey]
    struct Journey {
    let name: String
    let description: String
    let image: UIImage
    let progress: String
    let isLocked: Bool
    let onSelect: () -> ()
    }
    }
    Vitalii Malakhovskyi, BetterMe 17

    View Slide

  18. unidirectional
    Vitalii Malakhovskyi, BetterMe 18

    View Slide

  19. once somthing changed
    everything gets updated
    Vitalii Malakhovskyi, BetterMe 19

    View Slide

  20. main idea
    only valid
    state
    Vitalii Malakhovskyi, BetterMe 20

    View Slide

  21. wrong
    struct Interface {
    let programs: [Program]
    let temperatures: [Temperature]
    let RPMs: [RPM]
    enum Program {}
    enum Temperature {}
    enum RPM {}
    }
    Vitalii Malakhovskyi, BetterMe 21

    View Slide

  22. correct
    enum Interface {
    case handWash90Degree
    case wool30Degree
    case off
    }
    Vitalii Malakhovskyi, BetterMe 22

    View Slide

  23. Vitalii Malakhovskyi, BetterMe 23

    View Slide

  24. enum Props {
    case loading([Loading])
    case error(title: String, message: String, onReload: () -> ())
    case data([Data])
    struct Data {}
    struct Loading {}
    }
    Vitalii Malakhovskyi, BetterMe 24

    View Slide

  25. should not relay
    on previous data
    Vitalii Malakhovskyi, BetterMe 25

    View Slide

  26. single source
    of update
    Vitalii Malakhovskyi, BetterMe 26

    View Slide

  27. UIView/UIViewController
    Vitalii Malakhovskyi, BetterMe 27

    View Slide

  28. func render(props: Props) {
    self.props = props
    view.setNeedsLayout()
    }
    func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    /// redraw view state
    }
    Vitalii Malakhovskyi, BetterMe 28

    View Slide

  29. EXAMPLE
    Vitalii Malakhovskyi, BetterMe 29

    View Slide

  30. 1
    Vitalii Malakhovskyi, BetterMe 30

    View Slide

  31. Presenter <- View
    Vitalii Malakhovskyi, BetterMe 31

    View Slide

  32. ViewData should be observable
    Vitalii Malakhovskyi, BetterMe 32

    View Slide

  33. protocol ViewModel {
    var viewData: Property { get }
    }
    Vitalii Malakhovskyi, BetterMe 33

    View Slide

  34. class ViewController: UIViewController {
    func viewDidLoad() {
    viewModel.viewData.producer.startWithValues { _ in
    view.setNeedsLayout()
    }
    }
    func viewWillLayoutSubviews() {
    switch viewModel.viewData.value {
    ...
    }
    }
    }
    Vitalii Malakhovskyi, BetterMe 34

    View Slide

  35. how to achieve this?
    » reactive cocoa
    » rxswift
    » handmade observations
    » KVO
    Vitalii Malakhovskyi, BetterMe 35

    View Slide

  36. 2
    Vitalii Malakhovskyi, BetterMe 36

    View Slide

  37. Presenter <-> View
    Vitalii Malakhovskyi, BetterMe 37

    View Slide

  38. VIPER
    Vitalii Malakhovskyi, BetterMe 38

    View Slide

  39. /// View -> Presenter
    protocol ViewOutput {
    func viewIsReady()
    }
    /// Presenter -> View
    protocol PresenterOutput: {
    func receiveUpdate(with data: ViewData)
    }
    Vitalii Malakhovskyi, BetterMe 39

    View Slide

  40. space
    for bugs
    Vitalii Malakhovskyi, BetterMe 40

    View Slide

  41. 3
    Vitalii Malakhovskyi, BetterMe 41

    View Slide

  42. Presenter -> View
    Vitalii Malakhovskyi, BetterMe 42

    View Slide

  43. class ViewController: UIViewController {
    struct ViewData {}
    func render(viewData: ViewData) {
    self.viewData = viewData
    view.setNeedsLayout()
    }
    }
    struct Presenter {
    let render: (ViewData) -> ()
    func handleNewAppState(...) // calls render
    }
    Vitalii Malakhovskyi, BetterMe 43

    View Slide

  44. View has
    no dependencies
    Vitalii Malakhovskyi, BetterMe 44

    View Slide

  45. UIKit owns UIViewController
    store owns presenter
    Vitalii Malakhovskyi, BetterMe 45

    View Slide

  46. CODE!
    Vitalii Malakhovskyi, BetterMe 46

    View Slide

  47. * simple input
    * input + validation
    * multistate screen
    * animation
    * MVVM vc DD MVVM
    * VIPER vc DD VIPER
    * MVC vc DD MVC
    Vitalii Malakhovskyi, BetterMe 47

    View Slide

  48. GITHUB
    github.com/vmalakhovskiy/data-driven-vc
    Vitalii Malakhovskyi, BetterMe 48

    View Slide

  49. THANKS!
    Vitalii Malakhovskyi, BetterMe 49

    View Slide

  50. * Data-Driven View
    Controllers. Tips
    and Tricks
    * github
    * Redux
    Vitalii Malakhovskyi, BetterMe 50

    View Slide

  51. Questions?
    Vitalii Malakhovskyi, BetterMe 51

    View Slide

  52. purpleshirted
    Vitalii Malakhovskyi
    VitaliyMal
    vmalakhovskiy
    Vitalii Malakhovskyi, BetterMe 52

    View Slide