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.

7b2fdba8077c8495b3caa6f36d0928da?s=128

Marcin Krzyzanowski

October 19, 2015
Tweet

Transcript

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

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

  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”
  4. Storyboard » scenes » segues between scenes » controls used

    to trigger the segues
  5. Storyboard » graphical representation of a interface » visual editor:

    Interface Builder » not a code » structured XML document (compiled to nibs) » loaded in runtime
  6. None
  7. None
  8. Storyboard, meet Swift

  9. As it is » string based identifiers » UIViewController

  10. Problems » error prone refactoring » traversing view controllers/storyboards »

    massive Storyboard (not necessarily) » more
  11. Strings everywhere

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

    vc = storyboard.instantiateViewControllerWithIdentifier("MainViewController")
  13. Strings everywhere - refactoring week later storyboard.instantiateViewControllerWithIdentifier("ZweiMainViewController") *** Terminating app

    due to uncaught exception 'NSInvalidArgumentException', reason: 'Storyboard (<UIStoryboard: 0x7fea2871ccf0>) 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 )
  14. Strings everywhere - Refactoring func performSegueWithIdentifier(identifier: String, sender: AnyObject?) ***

    Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<NatalieExample.MainViewController: 0x7f93e2761eb0>) has no segue with identifier 'GoToMainView'' *** First throw call stack: ( 0 CoreFoundation 0x000000010634df65 __exceptionPreprocess + 165 1 libobjc.A.dylib 0x0000000107fdfdeb objc_exception_throw + 48 )
  15. UIViewController everywhere func instantiateInitialViewController() -> UIViewController? func instantiateViewControllerWithIdentifier(identifier: String) ->

    UIViewController returning type? I don't know.
  16. as! instantiateInitialViewController() as! OtherViewController Could not cast value of type

    'MainViewController' to 'OtherViewController'.
  17. Swift, meet Storyboard

  18. None
  19. compile time safety Strong Type System

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

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

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

    - source code
  23. Storyboard, Swift, meet Natalie

  24. None
  25. Natalie Storyboard Code Generator

  26. Natalie » Open Source (github: krzyzanowskim/Natalie) » CLI tool »

    Swift script » #!/usr/bin/env xcrun -sdk macosx swift » Homebrew » $ brew install natalie
  27. Storyboards.swift

  28. Natalie Integrates with Xcode Build Phases

  29. View Controllers struct Storyboards { struct Main { static func

    instantiateViewController<T: UIViewController>(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:
  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? } }
  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)
  32. Perform Segues vc.performSegue(MainViewController.Segue.ScreenOneSegue) override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue == MainViewController.Segue.ScreenOneSegue { // handle segue } }
  33. More » UITableView reusable cells » UICollectionView reusable cells »

    Compare segues (segue1 == segue2)
  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
  35. None
  36. Thank you Marcin Krzyżanowski blog.krzyzanowskim.com @krzyzanowskim