闭包是独立的功能块,可以在代码中传递和使用。Swift中的闭包类似于C和Objective-C中的代码块,闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用。这称为close over这些常量和变量。Swift为您处理捕获的所有内存管理。
全局和嵌套函数实际上是闭包的特殊情况。闭包采用以下三种形式之一
全局函数是具有名称且不捕获任何值的闭包。
嵌套函数是具有名称的闭包,可以从其闭包函数捕获值。
闭包表达式是用轻量级语法编写的未命名的闭包,可以从其周围的上下文中捕获值。
闭包表达式语法
闭包表达式语法具有以下一般形式:
{ (parameters) -> return type in
statements
}
尾随闭包
如果您需要将闭包表达式作为函数的最终参数传递给函数,并且闭包表达式很长,那么将其写为尾随闭包可能会很有用。您可以在函数调用的括号后面编写尾随闭包,即使尾随闭包仍然是函数的参数。使用尾随闭包语法时,不要在函数调用中为第一个闭包编写参数标签。一个函数调用可以包括多个结尾的闭包。
当闭包足够长而无法单行内联写入时,尾随闭包最有用。例如,Swift的Array类型有一个map(_:)方法,该方法将闭包表达式作为其单个参数。对数组中的每个项目调用一次闭包,并为该项目返回一个替代的映射值(可能是其他类型的)。通过在传递给闭包的代码中编写代码,可以指定映射的性质和返回值的类型map(_:)。
将提供的闭包应用于每个数组元素后,该map(_:)方法将返回一个包含所有新映射值的新数组,其顺序与原始数组中相应值的顺序相同。
特性
闭包可以从定义它的周围上下文中捕获常量和变量。然后,闭包可以从其主体内部引用和修改这些常量和变量的值,即使定义常量和变量的原始范围不再存在。
在Swift中,最简单的可以捕获值的闭包形式是嵌套函数,它写在另一个函数的主体内。嵌套函数可以捕获其外部函数的任何自变量,还可以捕获在外部函数内定义的任何常量和变量。
作为一种优化,Swift可能会捕获并存储值的副本,如果该值未由闭包更改,并且该值在创建闭包后也未更改。
Swift也可以处理不再需要变量时涉及的所有内存管理。如果将闭包分配给类实例的属性,并且闭包通过引用该实例或其成员来捕获该实例,则将在闭包和实例之间创建一个强引用。Swift使用捕获列表来打破这些强引用。
闭包是引用类型
将函数或闭包分配给常量或变量时,实际上就是在将该常量或变量设置为对该函数或闭包的引用。
逃逸闭包
当闭包作为函数的参数传递给闭包时,闭包被认为是对函数的转义,但是在函数返回后被调用。声明将闭包作为其参数之一的函数时,可以@escaping在参数的类型之前编写以指示允许对闭包进行转义。
闭包可以逃脱的一种方法是将其存储在函数外部定义的变量中。例如,许多启动异步操作的函数都将闭包参数用作完成处理程序。该函数在开始操作后返回,但是直到操作完成后才调用闭包-该闭包需要转义,稍后再调用。
var completionHandlers = [() -> Void]()
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}