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

Swift, Meet Storyboard

Swift, Meet Storyboard

Swift London (October 19, 2015) talk. Talk about Natalie - Storyboard Code Generator presenting my approach to the "problem" of Storyboards and Swift.

Marcin Krzyzanowski

October 19, 2015
Tweet

More Decks by Marcin Krzyzanowski

Other Decks in Programming

Transcript

  1. Swift London, 19 Oct 2015
    Swift, meet Storyboard

    View Slide

  2. Welcome
    Marcin Krzyżanowski
    blog.krzyzanowskim.com
    @krzyzanowskim

    View Slide

  3. Storyboards
    “A storyboard is a visual representation of the user
    interface of an iOS application, showing screens of
    content and the connections between those screens”

    View Slide

  4. Storyboard
    » scenes
    » segues between scenes
    » controls used to trigger
    the segues

    View Slide

  5. Storyboard
    » graphical representation of
    a interface
    » visual editor: Interface
    Builder
    » not a code
    » structured XML document
    (compiled to nibs)
    » loaded in runtime

    View Slide

  6. View Slide

  7. View Slide

  8. Storyboard,
    meet Swift

    View Slide

  9. As it is
    » string based identifiers
    » UIViewController

    View Slide

  10. Problems
    » error prone refactoring
    » traversing view controllers/storyboards
    » massive Storyboard (not necessarily)
    » more

    View Slide

  11. Strings everywhere

    View Slide

  12. Strings everywhere
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewControllerWithIdentifier("MainViewController")

    View Slide

  13. Strings everywhere - refactoring
    week later
    storyboard.instantiateViewControllerWithIdentifier("ZweiMainViewController")
    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
    'Storyboard () doesn't contain a view controller with identifier 'ZweiMainViewController''
    *** First throw call stack: (
    0 CoreFoundation 0x0000000104f88f65 __exceptionPreprocess + 165
    1 libobjc.A.dylib 0x0000000106c1adeb objc_exception_throw + 48
    2 UIKit 0x0000000105e855d4 -[UIStoryboard instantiateInitialViewController] + 0
    )

    View Slide

  14. Strings everywhere - Refactoring
    func performSegueWithIdentifier(identifier: String, sender: AnyObject?)
    *** Terminating app due to uncaught exception 'NSInvalidArgumentException',
    reason: 'Receiver ()
    has no segue with identifier 'GoToMainView''
    *** First throw call stack: (
    0 CoreFoundation 0x000000010634df65 __exceptionPreprocess + 165
    1 libobjc.A.dylib 0x0000000107fdfdeb objc_exception_throw + 48
    )

    View Slide

  15. UIViewController everywhere
    func instantiateInitialViewController() -> UIViewController?
    func instantiateViewControllerWithIdentifier(identifier: String) -> UIViewController
    returning type? I don't know.

    View Slide

  16. as!
    instantiateInitialViewController() as! OtherViewController
    Could not cast value of type
    'MainViewController'
    to 'OtherViewController'.

    View Slide

  17. Swift,
    meet Storyboard

    View Slide

  18. View Slide

  19. compile time safety
    Strong Type System

    View Slide

  20. Wouldn't be nice go from this:
    storyboard.instantiateViewControllerWithIdentifier("MainViewController")
    to this
    storyboard.instantiateViewController(MainViewController)
    and feel safe

    View Slide

  21. Parse and conquer
    Layer
    - .storyboard
    Layer
    - source code

    View Slide

  22. Parse and conquer
    Layer
    - .storyboard
    Layer
    - generator
    Layer
    - source code

    View Slide

  23. Storyboard, Swift,
    meet Natalie

    View Slide

  24. View Slide

  25. Natalie
    Storyboard Code Generator

    View Slide

  26. Natalie
    » Open Source (github: krzyzanowskim/Natalie)
    » CLI tool
    » Swift script
    » #!/usr/bin/env xcrun -sdk macosx swift
    » Homebrew
    » $ brew install natalie

    View Slide

  27. Storyboards.swift

    View Slide

  28. Natalie
    Integrates with Xcode
    Build Phases

    View Slide

  29. View Controllers
    struct Storyboards {
    struct Main {
    static func instantiateViewController(type: T.Type) -> T?
    static func instantiateMainViewController() -> MainViewController
    static func instantiateSecondViewController() -> ScreenTwoViewController
    }
    struct Settings {
    ...
    }
    }
    Instantiate view controllers:
    let vc = Storyboards.Main.instantiateViewConrtoller(MainViewConrtoller)
    let vc = Storyboards.Main.instantiateMainViewController()
    let vc = Storyboards.Main.instantiateSecondViewController()
    Notice: "vc" has right type:

    View Slide

  30. Segues
    extension MainViewController {
    enum Segue: String, CustomStringConvertible, SegueProtocol {
    case ScreenOneSegueButton = "Screen One Segue Button"
    var kind: SegueKind? // .Push, .Modal, etc...
    var identifier: String?
    var destination: UIViewController.Type?
    }
    }

    View Slide

  31. Segues
    var destination: UIViewController.Type? {
    switch (self) {
    case ScreenOneSegueButton:
    return ScreenOneViewController.self
    case ScreenOneSegue:
    return ScreenOneViewController.self
    }
    }
    in theory:
    MainViewController.Segue.ScreenOneSegue.destination!.init(nibName: nil, bundle: nil)

    View Slide

  32. Perform Segues
    vc.performSegue(MainViewController.Segue.ScreenOneSegue)
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue == MainViewController.Segue.ScreenOneSegue {
    // handle segue
    }
    }

    View Slide

  33. More
    » UITableView reusable cells
    » UICollectionView reusable cells
    » Compare segues (segue1 == segue2)

    View Slide

  34. Recap
    » Storyboard is external to the code
    » Strings are error prone
    » Swift is Strongly Typed
    » Middleman generator can create bridge between two
    worlds
    » Natalie

    View Slide

  35. View Slide

  36. Thank you
    Marcin Krzyżanowski
    blog.krzyzanowskim.com
    @krzyzanowskim

    View Slide