Closures Are Reference Types - from apple swift guide
In the example above,incrementBySevenandincrementByTenare constants, but the closures these constants refer to are still able to increment therunningTotalvariables that they have captured. This is because functions and closures are reference types.
Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. In the example above, it is the choice of closure that incrementByTenrefers to that is constant, and not the contents of the closure itself.
This also means that if you assign a closure to two different constants or variables, both of those constants or variables will refer to the same closure:
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// returns a value of 50
Escaping Closures - from apple swift guide
- Non-escaping closures(default for swift 3): captured objective ref no change
- Escaping Closures(default for swift 2): captured objective ref + 1
- var/let closures always escaping closures
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. When you declare a function that takes a closure as one of its parameters, you can write@escapingbefore the parameter’s type to indicate that the closure is allowed to escape.
One way that a closure can escape is by being stored in a variable that is defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed—the closure needs to escape, to be called later. For example:
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
The someFunctionWithEscapingClosure(_:)function takes a closure as its argument and adds it to an array that’s declared outside the function. If you didn’t mark the parameter of this function with@escaping, you would get a compiler error.
Marking a closure with @escapingmeans you have to refer toselfexplicitly within the closure. For example, in the code below, the closure passed tosomeFunctionWithEscapingClosure(_:)is an escaping closure, which means it needs to refer toselfexplicitly. In contrast, the closure passed tosomeFunctionWithNonescapingClosure(_:)is a nonescaping closure, which means it can refer toselfimplicitly.
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 } // escaping we have to add self
someFunctionWithNonescapingClosure { x = 200 } // nonescaping we dont need self
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
// Prints "200"
completionHandlers.first?()
print(instance.x)
// Prints "100"
Syntax
from fxxxswiftblock.com
As a variable:
var closureName: (ParameterTypes) -> (ReturnType)
As an optional variable:
var closureName: ((ParameterTypes) -> (ReturnType))?
As a type alias:
typealias ClosureType = (ParameterTypes) -> (ReturnType)
As a constant:
let closureName: ClosureType = { ... }
As an argument to a function call:
funcName({ (ParameterTypes) -> (ReturnType) in statements })
As a function parameter:
array.sort({ (item1: Int, item2: Int) -> Bool in return item1 < item2 })
As a function parameter with implied types:
array.sort({ (item1, item2) -> Bool in return item1 < item2 })
As a function parameter with implied return type:
array.sort({ (item1, item2) in return item1 < item2 })
As the last function parameter:
array.sort { (item1, item2) in return item1 < item2 }
As the last parameter, using shorthand argument names:
array.sort { return $0 < $1 }
As the last parameter, with an implied return value:
array.sort { $0 < $1 }
As the last parameter, as a reference to an existing function:
array.sort(<)
As a function parameter with explicit capture semantics:
array.sort({ [unowned self] (item1: Int, item2: Int) -> Bool in return item1 < item2 })
As a function parameter with explicit capture semantics and inferred parameters / return type:
array.sort({ [unowned self] in return $0 < $1 })