当闭包作为函数的参数传入时,很有可能这个闭包在函数返回之后才会被执行,这就是逃逸闭包。
在Swift中可以在参数名前标注 @noescape
来指明这个闭包是不允许逃逸出这个函数的。因为非逃逸闭包只能在函数体中被执行,不能脱离函数体执行,所以这使得编译器可以明确的知道运行时的上下文环境,进而做出优化。
比如, sort(_:)
方法可以接受一个用于元素比较的闭包参数,它被指明为 @noescape
,因为排序结束后这个闭包就没用了。
一般情况下,一些异步函数会使用逃逸闭包。这类函数会在异步操作开始之后立刻返回,但是闭包直到异步操作结束后才会被调用。比如网络请求中处理服务器返回请求的闭包。在这种情况下,逃逸闭包就可以派上用场了。一个常见的例子如下:
varhandlers: [()->Void] = [] func functionWithEscapingClosure(handler: () -> Void){ truehandlers.append(handler) }
因为编译器知晓非逃逸闭包的上下文环境,所以非逃逸闭包中可以不写 self
。
比如:
classA { truevarx truefunc doSometing{ truetruefunctionWithEscapingClosure{x=250} true} }
自动闭包,顾名思义是一种自动创建的闭包,用于包装函数参数的表达式,可以说是一种简便语法。
自动闭包不接受任何参数,被调用时会返回被包装在其中的表达式的值。
自动闭包的好处之二是让你能够延迟求值,因为代码段不会被执行直到你调用这个闭包,这样你就可以控制代码什么时候执行。
var students =["A","B","C"] letstudentsProvider ={ students.removeAtIndex(0) } studentsProvider()
尽管调用了 removeAtIndex()
方法,但是此时并不会执行,知道第三行调用了这个闭包方法。
这里注意 studentsProvider
与 studentsProvider()
二者的不同,前者的类型是 ()->String
指向了一个函数,后者的类型是 String
。
当闭包作为函数参数时,可以将参数标记 @autoclosure
来接收自动闭包。 @autoclosure
暗含了非逃逸闭包的特性,如果你想让这个自动闭包具有逃逸的特性需要更改标记为 @autoclosure(escaping)
。