Closures

The Sorted Method

                  let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
                
                  func backward(_ s1: String, _ s2: String) -> Bool {

    return s1 > s2

}

var reversedNames = names.sorted(by: backward)

// reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
                

Closure Expression Syntax

                  { (parameters) -> return type in

    statements

}
                
                  reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in

    return s1 > s2

})
                
                  reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
                

Inferring Type From Context

                  reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
                

Implicit Returns from Single-Expression Closures

                  reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
                

Shorthand Argument Names

                  reversedNames = names.sorted(by: { $0 > $1 } )
                

Operator Methods

                  reversedNames = names.sorted(by: >)
                

Trailing Closures

                  func someFunctionThatTakesAClosure(closure: () -> Void) {

    // function body goes here

}



// Here's how you call this function without using a trailing closure:



someFunctionThatTakesAClosure(closure: {

    // closure's body goes here

})



// Here's how you call this function with a trailing closure instead:



someFunctionThatTakesAClosure() {

    // trailing closure's body goes here

}
                
                  reversedNames = names.sorted() { $0 > $1 }
                
                  reversedNames = names.sorted { $0 > $1 }
                
                  let digitNames = [

    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",

    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"

]

let numbers = [16, 58, 510]
                
                  let strings = numbers.map { (number) -> String in

    var number = number

    var output = ""

    repeat {

        output = digitNames[number % 10]! + output

        number /= 10

    } while number > 0

    return output

}

// strings is inferred to be of type [String]

// its value is ["OneSix", "FiveEight", "FiveOneZero"]
                
                  func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void) {

    if let picture = download("photo.jpg", from: server) {

        completion(picture)

    } else {

        onFailure()

    }

}
                
                  loadPicture(from: someServer) { picture in

    someView.currentPicture = picture

} onFailure: {

    print("Couldn't download the next picture.")

}
                

Capturing Values

                  func makeIncrementer(forIncrement amount: Int) -> () -> Int {

    var runningTotal = 0

    func incrementer() -> Int {

        runningTotal += amount

        return runningTotal

    }

    return incrementer

}
                
                  func incrementer() -> Int {

    runningTotal += amount

    return runningTotal

}
                
                  let incrementByTen = makeIncrementer(forIncrement: 10)
                
                  incrementByTen()

// returns a value of 10

incrementByTen()

// returns a value of 20

incrementByTen()

// returns a value of 30
                
                  let incrementBySeven = makeIncrementer(forIncrement: 7)

incrementBySeven()

// returns a value of 7
                
                  incrementByTen()

// returns a value of 40
                

Closures Are Reference Types

                  let alsoIncrementByTen = incrementByTen

alsoIncrementByTen()

// returns a value of 50



incrementByTen()

// returns a value of 60
                

Escaping Closures

                  var completionHandlers = [() -> Void]()

func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {

    completionHandlers.append(completionHandler)

}
                
                  func someFunctionWithNonescapingClosure(closure: () -> Void) {

    closure()

}



class SomeClass {

    var x = 10

    func doSomething() {

        someFunctionWithEscapingClosure { self.x = 100 }

        someFunctionWithNonescapingClosure { x = 200 }

    }

}



let instance = SomeClass()

instance.doSomething()

print(instance.x)

// Prints "200"



completionHandlers.first?()

print(instance.x)

// Prints "100"
                
                  class SomeOtherClass {

    var x = 10

    func doSomething() {

        someFunctionWithEscapingClosure { [self] in x = 100 }

        someFunctionWithNonescapingClosure { x = 200 }

    }

}
                
                  struct SomeStruct {

    var x = 10

    mutating func doSomething() {

        someFunctionWithNonescapingClosure { x = 200 }  // Ok

        someFunctionWithEscapingClosure { x = 100 }     // Error

    }

}
                

Autoclosures

                  var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

print(customersInLine.count)

// Prints "5"



let customerProvider = { customersInLine.remove(at: 0) }

print(customersInLine.count)

// Prints "5"



print("Now serving \(customerProvider())!")

// Prints "Now serving Chris!"

print(customersInLine.count)

// Prints "4"
                
                  // customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]

func serve(customer customerProvider: () -> String) {

    print("Now serving \(customerProvider())!")

}

serve(customer: { customersInLine.remove(at: 0) } )

// Prints "Now serving Alex!"
                
                  // customersInLine is ["Ewa", "Barry", "Daniella"]

func serve(customer customerProvider: @autoclosure () -> String) {

    print("Now serving \(customerProvider())!")

}

serve(customer: customersInLine.remove(at: 0))

// Prints "Now serving Ewa!"
                
                  // customersInLine is ["Barry", "Daniella"]

var customerProviders: [() -> String] = []

func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {

    customerProviders.append(customerProvider)

}

collectCustomerProviders(customersInLine.remove(at: 0))

collectCustomerProviders(customersInLine.remove(at: 0))



print("Collected \(customerProviders.count) closures.")

// Prints "Collected 2 closures."

for customerProvider in customerProviders {

    print("Now serving \(customerProvider())!")

}

// Prints "Now serving Barry!"

// Prints "Now serving Daniella!"