当闭包被作为参数传递给函数时,闭包被称为转义函数,但在函数返回后被调用。当你声明一个将闭包作为其参数的函数时,你可以在参数的类型之前写入@escaping来表示允许闭包被转义。
闭包可以逃脱的一种方式是存储在函数外部定义的变量中。作为例子,许多启动异步操作的函数都将闭包参数作为完成处理程序。该函数在开始操作后返回,但在操作完成之前不会调用闭包 - 闭包需要转义,稍后调用。例如:
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
someFunctionWithEscapingClosure(_ :)函数将闭包作为其参数,并将其添加到在函数外部声明的数组。如果你没有用@escaping标记这个函数的参数,你会得到一个编译时错误。
用@escaping标记闭包意味着你必须在闭包中明确地引用自己。例如,在下面的代码中,传递给someFunctionWithEscapingClosure(_ :)的闭包是一个转义闭包,这意味着它需要明确地引用自己。相比之下,传递给someFunctionWithNonescapingClosure(_ :)的闭包是一个非转义闭包,这意味着它可以隐式引用自己。
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"