Escaping Closures - Swift

逃逸闭包和非逃逸闭包


逃逸闭包(escaping closure),什么是逃逸闭包?苹果官方给的定义是:当一个闭包作为一个参数传递给函数,但是它是在函数返回之后调用的,这时候,这个闭包就称为逃逸闭包。当你声明一个将闭包作为参数的函数时,你可以在参数的类型之前用 @escaping 来表明这个闭包是允许逃逸的。

闭包可以逃逸的一种方式是存储在函数之外定义的变量中。作为例子,许多启动异步操作的函数都将闭包参数放在异步执行完毕之后的操作中执行(completion handler)。该函数在开始操作后返回,但在操作完成之前不会调用闭包 — 闭包需要逃逸,稍后调用,举个例子:

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

someFunctionWithEscapingClosure(_ :) 函数将闭包作为其参数,并将其添加到在函数外声明的数组中。如果你没有用 @escaping 来标记这个函数的参数,你会得到一个编译时的错误。

将一个闭包用 @escaping 来标记的话,意味着你需要在闭包中明确的引用自身 self ,例如,在下面的代码中,传递给 someFunctionWithEscapingClosure(_:) 的闭包是逃逸闭包,这就意味着它必须要明确的引用自身 self , 相比之下,传递给 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"

非逃逸闭包示意图


closure-noescape.png

逃逸闭包示意图


closure-escape.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容