Closures
Closure Expressions
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"]
the above example shows that we use a backwardfunction as a value to be sent into the sorted function.
but this is written as a closure ordinarily.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
We can see the closures structure:
{
(parameters)->return typein
statements
}
Inferring Type From Context
At the above example, the sortedfunction always be called on a strings array, so its argument must be a function of type (String, String) -> Bool, so we don't need to written the whole form.
It can be written as below:
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
Implicit Returns from Single-Expression Closures
And if there only be a single expression in closures, we can omit the return as well.
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
Shorthand Argument Names
Simpler and simpler, as below:
reversedNames = names.sorted(by: { $0 > $1 } )
Operator Methods
Simplest!!!
reversedNames = names.sorted(by: > }
This > can be related to a function, actually, it dose a function.
Capturing Values
Warning!!!
Watch out this expression!
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
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
We can see the above example, due to the nested function incrementer capture the runningTotal, so runningTotal will remains even if incrementByTen finish, and incrementBySeven is not influenced.
Because the function type and closures type is reference types.
Same for closures, but it will may cause strong reference cycles, which we will learn how to solve.
Escaping Closures
If we need the closures excute after the function ends, we should use key word @escaping before the parameter’s type.
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
Let’s think!