Closures
Similar to blocks in ObjC.
{ (parameters) -> return type in
statements
}
Ex:
reversed = names.sort(
{ (s1: String, s2: String) -> Bool in
return s1 > s2
}
)
Inferring Type From Context
ex: reversed = names.sort( { s1, s2 in return s1 > s2 } )
here parameter type and return type is inferred .
Shorthand Argument Names
swift automatically provides shorthand argument names to inline closures, argument by $0, $1 , $2 ..so on.
reversed = names.sort( { $0 > $1 } )
Operator Functions
above can be written as shorter like
reversed = names.sort(>)
so above (>) operator is a function (overloaded operator.)
Trailing Closures
Its mostly used when want to pass closure as final argument and closure expression is long. that is written outside of and after the parenthesis of function call.
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
reversed = names.sort() { $0 > $1 }
if closure is the only parameter to method with trailing closure no need to write parenthesis.
reversed = names.sort { $0 > $1 }
Capturing Values
closure capture the value from the surrounding context in which it is defined.
“As an optimization, Swift may instead capture and store a copy of a value if that value is not mutated by a closure, and if that same value is not mutated after the closure is created.Swift also handles all memory management involved in disposing of variables when they are no longer needed.”
Swift uses capture lists to break these strong reference cycles, If closure is property of object.
functions and closures are reference types
If a closure is passed as an argument to a function and it is invoked after the function returns, the closure is escaping.
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns (means the closure is called after function completes).. you can write @noescape before the parameter name to indicate that the closure is not allowed to escape.
ex:
func someFunctionWithNonescapingClosure(@noescape
closure: () -> Void) {
closure()
}
swift 3 nonescape keyword is removed and its default behaviour in swift 3
@noescape means after function (to which closure passed as parameter) completes it is not allow to call closure. OR destroy closure reference after function completes.
Its compile time error if you make esacpe closure as nonescape which is capturing variable or constant.
Ex: below u can not make nonescape because it will capture array
completionHandlers and closure will get called on completion callback so its should escape.
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: () -> Void) {
completionHandlers.append(completionHandler)
}
Autoclosures
its a closure that is automatically created to wrap an expression that is passed as argument to function.
It does not take any argument but it can return value of expression.
Ex:
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serveCustomer(customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serveCustomer( { customersInLine.removeAtIndex(0) } )
// Prints "Now serving Alex!
this can be converted to autoclosure like:
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serveCustomer(@autoclosure customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serveCustomer(customersInLine.removeAtIndex(0))
// Prints "Now serving Ewa!