默认情况下,闭包表达式从其周围范围捕获常量和变量,并对强引用这些值。可以使用捕获列表显式地控制如何在闭包中捕获值。
捕获列表是在参数列表之前,以逗号分隔的表达式列表,由方括号包围。如果使用捕获列表,则必须使用in关键字,即使省略了参数名、参数类型和返回类型。
在创建闭包时,将初始化捕获列表中的条目。对于捕获列表中的每个条目,一个常量被初始化为周围范围中具有相同名称的常量或变量的值。例如,在下面的代码中,a包含在捕获列表中,而b没有,这给了它们不同的行为。
var a = 0
var b = 0
let closure = { [a] in
print(a, b)
}
a = 10
b = 10
closure()
// Prints "0 10"
有两种不同的事物命名为a,周围范围内的变量和闭包范围内的常量,但只有一个名为b的变量。当创建闭包时,内部作用域中的a使用外部作用域中的a值初始化,但它们的值不以任何特殊方式连接。 这意味着对闭包外a值的更改不会影响闭包内a的值,同时对闭包内a值的更改也不会影响闭包外a的值。 相比之下,在外部范围中只有一个名为b的变量,因此从闭包内或外的变化在这两个地方都是可见的。
当捕获的变量类型有引用语义时,则没有这种区别。例如,下面的代码中有两个名为x的事物,一个是外部作用域中的变量,另一个是内部作用域中的常量,但是由于引用语义,它们都引用同一个对象。
class SimpleClass {
var value: Int = 0
}
var x = SimpleClass()
var y = SimpleClass()
let closure = { [x] in
print(x.value, y.value)
}
如果表达式值的类型是一个类,您可以在捕获列表中将表达式标记为weak
或unowned
,以捕获对表达式值的weak
或unowned
引用。
myFunction { print(self.title) } // implicit strong capture
myFunction { [self] in print(self.title) } // explicit strong capture
myFunction { [weak self] in print(self!.title) } // weak capture
myFunction { [unowned self] in print(self.title) } // unowned capture
还可以将任意表达式绑定到捕获列表中的指定值。 创建闭包时将计算表达式,并使用指定的强度捕获值。 例如:
// Weak capture of "self.parent" as "parent"
myFunction { [weak parent = self.parent] in print(parent!.title) }
有关闭包表达式的更多信息和示例,请查看Closure Expressions
。有关捕获列表的更多信息和示例,请查看 ARC中的解决闭包的强引用循环。