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

Crossing the Chasm of Swift

Patrick Seda
September 22, 2017

Crossing the Chasm of Swift

Patrick Seda

September 22, 2017
Tweet

More Decks by Patrick Seda

Other Decks in Programming

Transcript

  1. Access Control class C class D file 2 class A

    class B file 1 module “consumer” // Class with a member variable. open class A { private var value }
  2. Access Control class C class D file 2 class A

    class B file 1 module “consumer” // Class with a member variable. open class A { fileprivate var value }
  3. Access Control class C class D file 2 class A

    class B file 1 module “consumer” // Class with a member variable. open class A { internal var value }
  4. Access Control class C class D file 2 class A

    class B file 1 module “consumer” // Class with a member variable. open class A { public var value // Accessible, no override }
  5. Access Control class C class D file 2 class A

    class B file 1 module “consumer” // Class with a member variable. open class A { open var value // Accessible, can override }
  6. Access Control Why is the default level internal? “When you

    write a simple single-target app, the code in your app is typically self-contained within the app and doesn’t need to be made available outside of the app’s module. The default access level of internal already matches this requirement. Therefore, you don’t need to specify a custom access level.” Because: Less typing!
  7. Named Model Types // Modeling a Finite-State Machine. // State

    of the system. enum AlarmState { case disarmed case armed case alarming } // System-wide events. enum Event { case arm case disarm case tripSensor }
  8. Named Model Types var currentState: AlarmState func handleEvent(_ event: Event)

    { switch event { case .arm: if (currentState == .disarmed) { currentState = .armed } case .disarm: currentState = .disarmed case .tripSensor: if (currentState == .armed) { currentState = .alarming } } }
  9. Named Model Types var currentState: AlarmState = .disarmed handleEvent(.arm) //

    currentState == .armed handleEvent(.tripSensor) // currentState == .alarming handleEvent(.disarm) // currentState == .disarmed handleEvent(.tripSensor) // currentState == .disarmed
  10. Named Model Types // Define some Gibson guitar types enum

    Gibson: String { case lesPaul case es355 case flyingV case sg } let myGuitar = Gibson.lesPaul print("My guitar is a \(myGuitar.rawValue)") let yourGuitar: Gibson = .flyingV print("Your guitar is a \(yourGuitar.rawValue)") Output: My guitar is a lesPaul Your guitar is a flyingV
  11. Named Model Types // Define some Gibson guitar types enum

    Gibson: String { case lesPaul = "Les Paul" case es355 = "ES355" case flyingV = "Flying V" case sg = "SG" } let myGuitar = Gibson.lesPaul print("My guitar is a \(myGuitar.rawValue)") let yourGuitar: Gibson = .flyingV print("Your guitar is a \(yourGuitar.rawValue)") Output: My guitar is a Les Paul Your guitar is a Flying V
  12. Named Model Types When should we use struct vs. class?

    “In all other cases, define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures.” Use a struct when: - Encapsulate few, simple data values - Data can be copied (passed by value) - Does not need inheritance
  13. Protocols for Design protocol MusicalInstrument { func makeSound() } protocol

    StringedInstrument: MusicalInstrument { var numStrings: Int { get } } extension StringedInstrument { func makeSound() { print("Plink") } } class Cello: StringedInstrument { var numStrings: Int = 4 func makeSound() { print(”Hurrm Hummm") } } class Bass: StringedInstrument { var numStrings: Int = 4 func makeSound() { print("A Boom Boom Boom") } }
  14. Protocols for Design class Musician { var instrument: MusicalInstrument? func

    perform() { instrument?.makeSound() } } let cello: MusicalInstrument = Cello() let bass: MusicalInstrument = Bass() let musician = Musician() musician.instrument = cello musician.perform() musician.instrument = bass musician.perform() Output: Hurrm Hummm A Boom Boom Boom
  15. Closures // Do some stuff and fire a callback. func

    increment(_ value: inout Int, onDone onDone: () -> Void) { value += 1 onDone() } // Define our callback. var doneCb = { print("Done! value = \(value)") } // Test it out. var value = 3; increment(&value, onDone: doneCb) increment(&value, onDone: doneCb) Done! value = 4 Done! value = 5 Output:
  16. Closures var queue = DispatchQueue.global() // Run using a thread

    pool. func execute(_ work: () -> Void) { queue.sync { work() } } // Create some work. var workItemOne = { print("Work item 1") } var workItemTwo = { print("Work item 2") } execute(workItemOne) execute(workItemTwo) Work item 1 Work item 2 Output:
  17. Closures var queue = DispatchQueue.global() // Run using a thread

    pool. func execute(_ work: () -> Void) { queue.async { work() } } // Create some work. var workItemOne = { print("Work item 1") } var workItemTwo = { print("Work item 2") } execute(workItemOne) execute(workItemTwo) error: closure use of non-escaping parameter 'work' may allow it to escape Output:
  18. Closures var queue = DispatchQueue.global() // Run using a thread

    pool. func execute(_ work: @escaping () -> Void) { queue.async { work() } } // Create some work. var workItemOne = { print("Work item 1") } var workItemTwo = { print("Work item 2") } execute(workItemOne) execute(workItemTwo) Work item 1 Work item 2 Output:
  19. Closures // Work to be executed in the future. var

    futures: [() -> Void] = [] func queue(future work: () -> Void) { futures.append(work) } // Queue up some closures. queue(future: { print("Hey!") }) queue(future: { print("What?") }) // Execute each closure. for future in futures { future() } error: passing non-escaping parameter 'future' to function expecting an @escaping closure Output:
  20. Closures // Work to be executed in the future. var

    futures: [() -> Void] = [] func queue(future work: @escaping () -> Void) { futures.append(work) } // Queue up some closures. queue(future: { print("Hey!") }) queue(future: { print("What?") }) // Execute each closure. for future in futures { future() } Hey! What? Output:
  21. Memory Leaks // A noble warrior. class Knight { var

    horse: Horse? deinit { print("[Knight] - deinit()") } } // A valiant steed. class Horse { var knight: Knight? deinit { print("[Horse] - deinit()") } }
  22. Memory Leaks // Create our knight. var hero: Knight? =

    Knight() // Create our horse. var stallion: Horse? = Horse() // Establish a beautiful friendship. hero?.horse = stallion stallion?.knight = hero // Clean up. print("Removing hero ...") hero = nil print("Removing stallion ...") stallion = nil Removing hero ... Removing stallion ... Output:
  23. Memory Leaks var hero strong strong strong var stallion strong

    <Knight instance> horse: <Horse instance> hero <Horse instance> knight: <Knight instance> stallion
  24. Memory Leaks var hero <Knight instance> horse: <Horse instance> hero

    strong strong var stallion <Horse instance> knight: <Knight instance> stallion
  25. Memory Leaks // A noble warrior. class Knight { var

    horse: Horse? deinit { print("[Knight] - deinit()") } } // A valiant steed. class Horse { var knight: Knight? deinit { print("[Horse] - deinit()") } }
  26. Memory Leaks // A noble warrior. class Knight { var

    horse: Horse? deinit { print("[Knight] - deinit()") } } // A valiant steed. class Horse { weak var knight: Knight? deinit { print("[Horse] - deinit()") } }
  27. Memory Leaks var hero strong strong var stallion strong weak

    <Horse instance> knight: <Knight instance> stallion <Knight instance> horse: <Horse instance> hero
  28. Memory Leaks var hero var stallion <Horse instance> knight: <Knight

    instance> stallion <Knight instance> horse: <Horse instance> hero
  29. Memory Leaks // Create our knight. var hero: Knight? =

    Knight() // Create our horse. var stallion: Horse? = Horse() // Establish a beautiful friendship. hero?.horse = stallion stallion?.knight = hero // Clean up. print("Removing hero ...") hero = nil print("Removing stallion ...") stallion = nil Removing hero ... [Knight] - deinit() Removing stallion ... [Horse] - deinit() Output:
  30. Memory Leaks // A noble warrior. class Knight { var

    esquire: Esquire? deinit { print("[Knight] - deinit()") } } // A knight’s assistant. class Esquire { var knight: Knight init(_ knight: Knight) { self.knight = knight } deinit { print("[Esquire] - deinit()") } }
  31. Memory Leaks // Create our knight. var hero: Knight? =

    Knight() // Create and assign our assistant. hero?.esquire = Esquire(hero!) // Clean up. print("Removing hero ...") hero = nil Removing hero ... Output:
  32. Memory Leaks var hero <Knight instance> esquire: <Esquire instance> hero

    <Esquire instance> knight: <Knight instance> esquire strong strong strong
  33. Memory Leaks var hero strong strong <Knight instance> esquire: <Esquire

    instance> hero <Esquire instance> knight: <Knight instance> esquire
  34. Memory Leaks // A noble warrior. class Knight { var

    esquire: Esquire? deinit { print("[Knight] - deinit()") } } // A knight’s assistant. class Esquire { unowned var knight: Knight init(_ knight: Knight) { self.knight = knight } deinit { print("[Esquire] - deinit()") } }
  35. Memory Leaks var hero strong strong unowned <Knight instance> esquire:

    <Esquire instance> hero <Esquire instance> knight: <Knight instance> esquire
  36. Memory Leaks var hero <Knight instance> esquire: <Esquire instance> hero

    <Esquire instance> knight: <Knight instance> esquire
  37. Memory Leaks // Create our knight. var hero: Knight? =

    Knight() // Create and assign our assistant. hero?.esquire = Esquire(hero!) // Clean up. print("Removing hero ...") hero = nil Removing hero ... [Knight] - deinit() [Esquire] - deinit() Output: