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

Protocol-Oriented MVVM

Protocol-Oriented MVVM

With Swift 2.0 came Protocol Extensions, which make Swift a Protocol-Oriented Programming Language. Learn what that means and how to apply protocol extensions to create beautiful and robust code without ever defaulting to subclassing.

By Natasha the Robot http://natashatherobot.com

Powered by http://xebia.com

do{iOS} conference

November 09, 2015
Tweet

More Decks by do{iOS} conference

Other Decks in Programming

Transcript

  1. POMVVM
    @NATASHATHEROBOT

    View Slide

  2. View Slide

  3. View Slide

  4. "Swift Is a Protocol-Oriented
    Programming Language"
    — Dave Abrahams, Professor of Blowing-Your-Mind

    View Slide

  5. UITableViewDelegate
    UITableViewDataSource
    UITextFieldDelegate
    NSURLSessionDelegate
    CLLocationManagerDelegate
    MCSessionDelegate

    View Slide

  6. !

    View Slide

  7. !

    View Slide

  8. !

    View Slide

  9. !

    View Slide

  10. Artsy Engineering: MVVM in Swift

    View Slide

  11. MODEL
    let amount = 6729383.99

    View Slide

  12. VIEW
    Your balance is $6,729,383.99

    View Slide

  13. VIEWMODEL
    struct AccountViewModel {
    let displayBalance: String
    init(model: BankAccount) {
    let formattedBalance = model.balance.currencyValue
    displayBalance = "Your balance is \(formattedBalance)"
    }
    }

    View Slide

  14. VIEWCONTROLLER
    var viewModel = ViewModel(model: Account)

    View Slide

  15. View Slide

  16. View Slide

  17. View Slide

  18. VIEWCONTROLLER
    var viewModel = ViewModel(model: Account)

    View Slide

  19. PROTOCOLS
    !!!

    View Slide

  20. View Slide

  21. THE PROBLEM
    class SwitchWithTextTableViewCell: UITableViewCell {
    func configure(
    title: String,
    titleFont: UIFont,
    titleColor: UIColor,
    switchOn: Bool,
    switchColor: UIColor = .purpleColor(),
    onSwitchToggleHandler: onSwitchToggleHandlerType? = nil)
    {
    // configure views here
    }
    }

    View Slide

  22. PROTOCOLS TO
    THE RESCUE !

    View Slide

  23. protocol SwitchWithTextCellProtocol {
    var title: String { get }
    var titleFont: UIFont { get }
    var titleColor: UIColor { get }
    var switchOn: Bool { get }
    var switchColor: UIColor { get }
    func onSwitchTogleOn(on: Bool)
    }

    View Slide

  24. extension SwitchWithTextCellProtocol {
    var switchColor: UIColor {
    return .purpleColor()
    }
    }

    View Slide

  25. class SwitchWithTextTableViewCell: UITableViewCell {
    func configure(withDelegate delegate: SwitchWithTextCellProtocol)
    {
    // configure views here
    }
    }

    View Slide

  26. struct MinionModeViewModel: SwitchWithTextCellProtocol {
    var title = "Minion Mode!!!"
    var switchOn = true
    var switchColor: UIColor {
    return .yellowColor()
    }
    func onSwitchTogleOn(on: Bool) {
    if on {
    print("The Minions are here to stay!")
    } else {
    print("The Minions went out to play!")
    }
    }
    }

    View Slide

  27. CELLFORROWATINDEXPATH
    // YourViewController.swift
    let cell = tableView.dequeueReusableCellWithIdentifier("SwitchWithTextTableViewCell",
    forIndexPath: indexPath) as! SwitchWithTextTableViewCell
    // this is where the magic happens!
    cell.configure(withDelegate: MinionModeViewModel())
    return cell

    View Slide

  28. !

    View Slide


  29. View Slide

  30. protocol SwitchWithTextCellDataSource {
    var title: String { get }
    var switchOn: Bool { get }
    }
    protocol SwitchWithTextCellDelegate {
    func onSwitchTogleOn(on: Bool)
    var switchColor: UIColor { get }
    var textColor: UIColor { get }
    var font: UIFont { get }
    }

    View Slide

  31. // SwitchWithTextTableViewCell
    func configure(withDataSource dataSource: SwitchWithTextCellDataSource,
    delegate: SwitchWithTextCellDelegate?)
    {
    // configure views here
    }

    View Slide

  32. struct MinionModeViewModel: SwitchWithTextCellDataSource {
    var title = "Minion Mode!!!"
    var switchOn = true
    }

    View Slide

  33. extension MinionModeViewModel: SwitchWithTextCellDelegate {
    var switchColor: UIColor {
    return .yellowColor()
    }
    func onSwitchTogleOn(on: Bool) {
    if on {
    print("The Minions are here to stay!")
    } else {
    print("The Minions went out to play!")
    }
    }
    }

    View Slide

  34. // SettingsViewController
    let viewModel = MinionModeViewModel()
    cell.configure(withDataSource: viewModel, delegate: viewModel)
    return cell

    View Slide

  35. !

    View Slide

  36. @MHOLLEMANS: MIXINS
    AND TRAITS IN SWIFT 2.0

    View Slide

  37. View Slide

  38. View Slide

  39. class AIPlayer: GameObject, AITrait, GunTrait, RenderTrait, HealthTrait {
    ...
    }
    class ZapMonster: GameObject, GunTrait, RenderTrait, HealthTrait, MovementTrait {
    ...
    }

    View Slide

  40. ! "

    View Slide

  41. protocol TextPresentable {
    var text: String { get }
    var textColor: UIColor { get }
    var font: UIFont { get }
    }
    protocol SwitchPresentable {
    var switchOn: Bool { get }
    var switchColor: UIColor { get }
    func onSwitchTogleOn(on: Bool)
    }

    View Slide

  42. protocol ImagePresentable {
    var imageName: String { get }
    }
    protocol TextFieldPresentable {
    var placeholder: String { get }
    var text: String { get }
    func onTextFieldDidEndEditing(textField: UITextField)
    }

    View Slide

  43. extension TextPresentable {
    var textColor: UIColor {
    return .blackColor()
    }
    var font: UIFont {
    return .systemFontOfSize(17)
    }
    }

    View Slide

  44. !!!
    class SwitchWithTextTableViewCell: UITableViewCell {
    private var delegate: T?
    func configure(withDelegate delegate: T) {
    // configure views here
    }
    }

    View Slide

  45. extension MinionModeViewModel: TextPresentable {
    var text: String { return "Minion Mode" }
    var textColor: UIColor { return .blackColor() }
    var font: UIFont { return .systemFontOfSize(17.0) }
    }

    View Slide

  46. extension MinionModeViewModel: SwitchPresentable {
    var switchOn: Bool { return false }
    var switchColor: UIColor { return .yellowColor() }
    func onSwitchTogleOn(on: Bool) {
    if on {
    print("The Minions are here to stay!")
    } else {
    print("The Minions went out to play!")
    }
    }
    }

    View Slide

  47. let cell = tableView.dequeueReusableCellWithIdentifier("SwitchWithTextTableViewCell",
    forIndexPath: indexPath) as! SwitchWithTextTableViewCell
    let viewModel = MinionModeViewModel()
    cell.configure(withDelegate: viewModel)
    return cell

    View Slide

  48. !"#

    View Slide

  49. "Change is the only constant."
    — Unknown

    View Slide

  50. View Slide

  51. class SwitchWithTextTableViewCell: UITableViewCell {
    }

    View Slide

  52. extension MinionModeViewModel: ImagePresentable {
    var imageName: String { return "minionParty.png" }
    }

    View Slide

  53. !"

    View Slide

  54. > Use Protocols to Configure Your Views
    > Use Protocol Extensions for Defaults
    > Use ViewModels to Provide Data for the Protocols

    View Slide

  55. HOW CAN WE
    MAKE THIS
    BETTER?

    View Slide