发布于 2015-06-14 01:53:29 | 173 次阅读 | 评论: 0 | 来源: 网络整理
闭包可以在其定义的上下文中捕获常量或变量。 即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。 嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
下例为一个叫做makeIncrementor
的函数,其包含了一个叫做incrementor
嵌套函数。 嵌套函数incrementor
从上下文中捕获了两个值,runningTotal
和amount
。 之后makeIncrementor
将incrementor
作为闭包返回。 每次调用incrementor
时,其会以amount
作为增量增加runningTotal
的值。
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
makeIncrementor
返回类型为() -> Int
。 这意味着其返回的是一个函数,而不是一个简单类型值。 该函数在每次调用时不接受参数只返回一个Int
类型的值。 关于函数返回其他函数的内容,请查看函数类型作为返回类型。
makeIncrementor
函数定义了一个整型变量runningTotal
(初始为0) 用来存储当前跑步总数。 该值通过incrementor
返回。
makeIncrementor
有一个Int
类型的参数,其外部命名为forIncrement
, 内部命名为amount
,表示每次incrementor
被调用时runningTotal
将要增加的量。
incrementor
函数用来执行实际的增加操作。 该函数简单地使runningTotal
增加amount
,并将其返回。
如果我们单独看这个函数,会发现看上去不同寻常:
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
incrementor
函数并没有获取任何参数,但是在函数体内访问了runningTotal
和amount
变量。这是因为其通过捕获在包含它的函数体内已经存在的runningTotal
和amount
变量而实现。
由于没有修改amount
变量,incrementor
实际上捕获并存储了该变量的一个副本,而该副本随着incrementor
一同被存储。
然而,因为每次调用该函数的时候都会修改runningTotal
的值,incrementor
捕获了当前runningTotal
变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当makeIncrementor
结束时候并不会消失,也保证了当下一次执行incrementor
函数时,runningTotal
可以继续增加。
注意:
Swift 会决定捕获引用还是拷贝值。
您不需要标注amount
或者runningTotal
来声明在嵌入的incrementor
函数中的使用方式。
Swift 同时也处理runingTotal
变量的内存管理操作,如果不再被incrementor
函数使用,则会被清除。
下面代码为一个使用makeIncrementor
的例子:
let incrementByTen = makeIncrementor(forIncrement: 10)
该例子定义了一个叫做incrementByTen
的常量,该常量指向一个每次调用会加10的incrementor
函数。 调用这个函数多次可以得到以下结果:
incrementByTen()
// 返回的值为10
incrementByTen()
// 返回的值为20
incrementByTen()
// 返回的值为30
如果您创建了另一个incrementor
,其会有一个属于自己的独立的runningTotal
变量的引用。 下面的例子中,incrementBySevne
捕获了一个新的runningTotal
变量,该变量和incrementByTen
中捕获的变量没有任何联系:
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
// 返回的值为7
incrementByTen()
// 返回的值为40
注意:
如果您将闭包赋值给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。
Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 闭包引起的循环强引用。