Swift计数闭包为何能持久保留内部捕获变量的状态值?
计数闭包独立存储值的核心原理
你产生困惑的核心原因是把普通函数的局部变量生命周期规则,和闭包的捕获语义做了等同,核心逻辑拆成几点就很容易理解:
- 普通函数的局部变量默认存在栈内存上,函数跑完、栈帧销毁后,局部变量会被直接回收,下次再调用函数会重新创建、初始化所有局部变量——这也是你觉得
counter每次调用都会重置为0的依据,这个规则在没有闭包捕获的场景下是完全成立的。 - 一旦函数里定义的闭包引用了函数作用域内的局部变量,Swift 会自动把这类被捕获的变量从栈内存挪到堆上存储,闭包本身会持有这个变量的强引用:只要闭包没被销毁,被它捕获的变量就会一直存在,不会跟着函数执行结束被回收。
- 每次调用
countingClosure()都是一次完全独立的函数执行,会生成一套全新的局部变量:- 第一次调用生成
counter1时,会创建一个初始值为0的新counter,被counter1持有的闭包单独捕获 - 第二次调用生成
counter2时,会再创建另一个初始值为0的新counter,和前一个counter没有任何关系,被counter2持有的闭包单独捕获
- 第一次调用生成
你后面调用counter1()、counter2()的时候,根本不会重新走countingClosure()里var counter = 0这行初始化代码——这行代码只有你主动调用countingClosure()的时候才会执行。调用返回的闭包时,只会跑闭包内部的计数逻辑,操作的是闭包自己捕获、一直存在堆上的独立counter变量,当然不会重置,两个闭包的计数值也完全互不干扰。
你可以写段简单代码验证这个逻辑:
let counter3 = countingClosure() let counter3Shared = counter3 // 把同一个闭包实例赋值给另一个变量 counter3() // 返回1 counter3Shared() // 返回2
两个变量指向同一个闭包实例、共享同一个被捕获的counter,计数是连续累加的,刚好和counter1、counter2独立计数的表现对应上。
内容的提问来源于stack exchange,提问作者OxfordSi
相关产品推荐
相关产品推荐

