捕获值(Capturing Values)
闭包可以在其定义的上下文中捕获常量或变量。 即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
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 使用捕获列表来打破这种强引用环。更多信息,请参考 闭包引起的循环强引用。
易百教程移动端:请扫描本页面底部(右侧)二维码并关注微信公众号,回复:"教程" 选择相关教程阅读或直接访问:http://m.yiibai.com 。
加QQ群啦,易百教程官方技术学习群
注意:建议每个人选自己的技术方向加群,同一个QQ最多限加 3 个群。
- Java技术群: 227270512 (人数:2000,免费:否)
- MySQL/SQL群: 418407075 (人数:2000,免费:否)
- 大数据开发群: 655154550 (人数:2000,免费:否)
- Python技术群: 287904175 (人数:2000,免费:否)
- 人工智能深度学习: 456236082 (人数:2000,免费:否)
- 测试工程师(新群): 415553199 (人数:1000,免费:否)
- 前端技术群(新群): 410430016 (人数:1000,免费:是)
- C/C++技术(新群): 629264796 (人数:1000,免费:是)
- Node.js技术(新群): 621549808 (人数:1000,免费:是)
- PostgreSQL数据库(新群): 539504187 (人数:1000,免费:是)
- Linux技术: 479429477 (人数:2000,免费:否)
- PHP开发者: 460153241 (人数:2000,免费:否)
- Oracle数据库: 175248146 (人数:2000,免费:否)
- C#/ASP.Net开发者: 579821706 (人数:2000,免费:是)
- 数据分析师: 397883996 (人数:2000,免费:是)R语言,Matlab语言等技术