在关闭中捕获值

时间:2016-04-02 21:13:57

标签: swift memory-management

从Apple Swift编程指南(2.2)中可以看出

  

闭包可以从定义它的周围上下文中捕获常量和变量。然后闭包可以引用并修改其体内的常量和变量的值,即使定义常量和变量的原始范围不再存在。

示例:

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30

问题是如何保存值而不是重置?我来自C背景,这看起来像3个函数调用和3个不同的堆栈帧。但价值似乎没有被覆盖。这是否意味着如果闭包使用其周围的上下文变量,它不会被编译器擦除,如果使用不正确会导致内存泄漏?

1 个答案:

答案 0 :(得分:2)

  

这是否意味着如果闭包使用其周围的上下文变量,它不会被编译器擦除,如果使用不正确会导致内存泄漏?

当然,但这不是在这种情况下发生的事情。让我分解一下。从makeIncrementer函数开始:

var runningTotal = 0
func incrementer() -> Int {
    runningTotal += amount
    return runningTotal
}

func incrementer指的是runningTotal,它位于自己身体外的范围内。因此,runningTotal 。{/ 1>

现在考虑周围函数func incrementer的作用:

makeIncrementer

声明func makeIncrementer(forIncrement amount: Int) -> () -> Int { // ... func incrementer() -> Int { // ... } return incrementer } 并将其返回。所以现在考虑当我们调用周围的函数时会发生什么:

func incrementer

最后一行调用 func makeIncrementer(forIncrement amount: Int) -> () -> Int { // ... return incrementer } let incrementByTen = makeIncrementer(forIncrement: 10) ,我们刚刚说过它会返回一个函数。它还将该函数分配给变量makeIncrementer 。这是本地(自动)变量。所以,是的,这个函数被保留,但只有incrementByTen存在,这不会很长,因为它只是作为一个自动局部变量在堆栈上。

但是只要incrementByTen 生存,它就会保留该功能,而我们在开始时说的那个功能已经捕获了incrementByTen并且正在维护它一种浮动的局部空间。因此runningTotal指向的函数可以多次调用,浮动incrementByTen可以保持生存并不断增加。