值捕获 2个月前

编程语言
229
值捕获

值捕获

闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。

Swift 中,可以捕获值的闭包的最简单形式是嵌套函数,也就是定义在其他函数的函数体内的函数。嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。

举个例子,这有一个叫做 makeIncrementer 的函数,其包含了一个叫做 incrementer 的嵌套函数。嵌套函数 incrementer() 从上下文中捕获了两个值,runningTotalamount。捕获这些值之后,makeIncrementerincrementer 作为闭包返回。每次调用 incrementer 时,其会以 amount 作为增量增加 runningTotal 的值。

funcmakeIncrementer(forIncrementamount: Int) -> () ->Int {
var runningTotal =0
funcincrementer() ->Int {
        runningTotal += amount
return runningTotal
    }
return incrementer
}

makeIncrementer 返回类型为 () -> Int。这意味着其返回的是一个 函数 ,而非一个简单类型的值。该函数在每次调用时不接受参数,只返回一个 Int 类型的值。关于函数返回其他函数的内容,请查看 函数类型作为返回类型

makeIncrementer(forIncrement:) 函数定义了一个初始值为 0 的整型变量 runningTotal,用来存储当前总计数值。该值为 incrementer 的返回值。

makeIncrementer(forIncrement:) 有一个 Int 类型的参数,其外部参数名为 forIncrement,内部参数名为 amount,该参数表示每次 incrementer 被调用时 runningTotal 将要增加的量。makeIncrementer 函数还定义了一个嵌套函数 incrementer,用来执行实际的增加操作。该函数简单地使 runningTotal 增加 amount,并将其返回。

如果我们单独考虑嵌套函数 incrementer(),会发现它有些不同寻常:

funcincrementer() ->Int {
    runningTotal += amount
return runningTotal
}

incrementer() 函数并没有任何参数,但是在函数体内访问了 runningTotalamount 变量。这是因为它从外围函数捕获了 runningTotalamount 变量的 引用 。捕获引用保证了 runningTotalamount 变量在调用完 makeIncrementer 后不会消失,并且保证了在下一次执行 incrementer 函数时,runningTotal 依旧存在。

注意

为了优化,如果一个值不会被闭包改变,或者在闭包创建后不会改变,Swift 可能会改为捕获并保存一份对值的拷贝。

Swift 也会负责被捕获变量的所有内存管理工作,包括释放不再需要的变量。

下面是一个使用 makeIncrementer 的例子:

let incrementByTen =makeIncrementer(forIncrement:10)

该例子定义了一个叫做 incrementByTen 的常量,该常量指向一个每次调用会将其 runningTotal 变量增加 10incrementer 函数。调用这个函数多次可以得到以下结果:

incrementByTen()
// 返回的值为10
incrementByTen()
// 返回的值为20
incrementByTen()
// 返回的值为30

如果你创建了另一个 incrementer,它会有属于自己的引用,指向一个全新、独立的 runningTotal 变量:

let incrementBySeven =makeIncrementer(forIncrement:7)
incrementBySeven()
// 返回的值为7

再次调用原来的 incrementByTen 会继续增加它自己的 runningTotal 变量,该变量和 incrementBySeven 中捕获的变量没有任何联系:

incrementByTen()
// 返回的值为40

注意

如果你将闭包赋值给一个类实例的属性,并且该闭包通过访问该实例或其成员而捕获了该实例,你将在闭包和该实例间创建一个循环强引用。Swift 使用捕获列表来打破这种循环强引用。更多信息,请参考 闭包引起的循环强引用

image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2223494
累计阅读

热门教程文档

C++
73小节
Vue
25小节
10.x
88小节
Next
43小节
React Native
40小节