Consider this class:
class A {
var closure: (() -> Void)?
func someMethod(closure: @escaping () -> Void) {
self.closure = closure
}
}
someMethod
assigns the closure passed in, to a property in the class.
Now here comes another class:
class B {
var number = 0
var a: A = A()
func anotherMethod() {
a.someMethod { self.number = 10 }
}
}
If I call anotherMethod
, the closure { self.number = 10 }
will be stored in the instance of A
. Since self
is captured in the closure, the instance of A
will also hold a strong reference to it.
That's basically an example of an escaped closure!
You are probably wondering, "what? So where did the closure escaped from, and to?"
The closure escapes from the scope of the method, to the scope of the class. And it can be called later, even on another thread! This could cause problems if not handled properly.
By default, Swift doesn't allow closures to escape. You have to add @escaping
to the closure type to tell the compiler "Please allow this closure to escape". If we remove @escaping
:
class A {
var closure: (() -> Void)?
func someMethod(closure: () -> Void) {
}
}
and try to write self.closure = closure
, it doesn't compile!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…