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

Storyboards Revisited

Paul Stringer
November 09, 2016

Storyboards Revisited

Storyboards are a powerful yet sometimes maligned tool for controlling the flow of your iOS app through configuration not code.

The storyboard approach in theory allows a clean separation of flow and presentation that provides greater flexibility to change. The reality though is that view controller code typically ends up becoming deeply entwined with the storyboard itself, leading to inflexible, oft duplicated code. This approach can leave many an experienced developer wondering "is it worth it?" and becoming wary of its use.

In this session we take a fresh cut - we pick up the story where 'Clean Architecture' approaches end and learn about a powerful approach to maintaining the separation of storyboard and view controller that delivers the promise of flexibility and less configuration in our code.

This talk will share a technique that makes powerful use one of the oldest but least understood design patterns in the book coupled with the modern language features of Swift for a story with an ending you don't want to miss!

Learn how to make Storyboards an even more compelling tool that can be at the heart of the clean architecture of your Swift app.

Paul Stringer

November 09, 2016
Tweet

More Decks by Paul Stringer

Other Decks in Technology

Transcript

  1. –Johnny Appleseed “A storyboard file captures your entire user interface

    in one place and lets you define both the individual view controllers and the transitions between those view controllers. As a result, storyboards capture the flow of your overall user interface in addition to the content you present.”
  2. – The Pragmatic Programmer, Andy Hunt, David Thomas. “You may

    be able to implement several different projects using the same application engine, but with different metadata.”
  3. Storyboards • Far less boiler-plate code to read, write, maintain

    • Powerful tool for creating and previewing layout • Quickly visualise the flow of the User Interface • Expressed in a way that’s closest to the domain
  4. The ‘Segwayue’ Problem override func prepare(for segue: UIStoryboardSegue, sender: Any?)

    { switch segue.identifier! { case "showDetail": let editorViewController = segue.destination as! DetailViewController ... break; default: break; } }
  5. The ‘Segue’ Problem • ‘String-Typing' identifier based code • View

    Controller code dependant on Storyboards • View Controllers dependant on other View Controllers • Lots of Switch statements
  6. –The Pragmatic Progammer, Metaprogramming, Andy Hunt, David Thomas. “Our goal

    is to think declaratively (specifying what is to be done, not how) and to create highly dynamic and adaptable programs. - We do this by programming for the general case and put the specifics somewhere else”
  7. Highly Dynamic and Adaptable • Generalise handling of Segue code

    • Remove Switch statements • Move specifics outside of View Controllers • Make Storyboards ‘Orthogonal’ to the code
  8. override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let destination

    = segue.destination as! DetailViewController let object = objectForRowAtSelectedIndexPath() destination.model = DetailViewModel(name: object.name) } private func objectForRowAtSelectedIndexPath() -> DetailEntityObject { … } Strongly Coupled View Controllers Configuring Destination View Controllers
  9. –David Wheeler “All problems in computer science can be solved

    by another level of indirection… …except for the problem of too many levels of indirection”
  10. Highly Dynamic and Adaptable 1. Introduce a new ‘intermediary’ to

    coordinate segues 2. Move responsibility for prepare(for segue:) to the intermediary 3. Determine the correct code path to prepare for the destination 4. Without String-Typing, Switch Statements, Forced Casts!
  11. Design Patterns, Elements of Reusable Object-Orientated Software Gamma, Helm,Johnson, Vlissides

    “Visitor pattern lets you add operations to classes without changing them. Visitor achieves this by using a technique called double-dispatch. “The operation that gets executed depends on both the type of Visitor and the type of Element it visits.” The Visitor Pattern
  12. class ChooseBeverageViewController: UIViewController { override func prepare(for segue: UIStoryboardSegue, sender:

    Any?) { // Prepare OrderSummaryViewController ... } … } Refactoring Segues Move Responsibility for prepare(for segue:)
  13. class ChooseBeverageViewController: StoryboardViewController { … } class StoryboardViewController { var

    sceneVisitor: StoryboardSceneVisitor? override func prepare(for segue: UIStoryboardSegue, sender: Any?) { sceneVisitor?.prepare(for: segue) } } Refactoring Segues Delegate Segue Responsibilities to the Visitor
  14. struct StoryboardSceneVisitor { func prepare(for segue: UIStoryboardSegue) { guard let

    destination = segue.destination as? StoryboardVisitableScene else { return } destination.accept(visitor: self) } } Refactoring Segues Dispatching the Visitor to the Destination public protocol StoryboardVisitableScene { func accept(visitor: StoryboardSceneVisitor) }
  15. extension OrderSummaryViewController: StoryboardVisitableScene { func accept(visitor: StoryboardSceneVisitor) { visitor.visit(self) }

    } Refactoring Segues Add conformance to destination View Controller and extend Visitor extension StoryboardSceneVisitor { func visit(_ scene: OrderSummaryViewController) { // Prepare OrderSummaryViewController ... } }
  16. Orthogonal Design • Using Storyboards we remain close to the

    domain • Metaprogramming suggested we move details outside of code • Using classic Design Patterns we added flexibility to our code • Changes in Storyboards don’t require changes in our code
  17. –The Pragmatic Programmer “If we were using the same kind

    of tools that produced the basic dumb-terminal applications 20 years ago, we’d never get anything done.”