Escaping Closures
Escaping Closures
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.
As an example, many functions that start an asynchronous operation take a closure argument as a completion handler.
1
2
3
4
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
Avoid Strong Reference Cycle
If you want to capture
self
, writeself
explicityly when you use it, or includeself
in the closure’s capture list. Writingself
explicitly let you express your intent, and reminds you to confirm that there isn’t a reference cycle.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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"
Escaping closure can’t capture a mutable reference to self
when self
is an instance of a structure or an enumeration.
Structures and enumerations don’t allow shared mutability.
1
2
3
4
5
6
7
struct SomeStruct {
var x = 10
mutating func doSomething() {
someFunctionWithNonescapingClosure { x = 200 } // Ok
someFunctionWithEscapingClosure { x = 100 } // Error
}
}
This post is licensed under CC BY 4.0 by the author.