【问题标题】:How are values captured when assigning a function to something that retains a closure将函数分配给保留闭包的东西时如何捕获值
【发布时间】:2015-11-13 10:51:48
【问题描述】:
如果我有这样的课程:
class Example {
var emptyBlock: (Void -> Void)?
var string: String = "Here's some string"
func someFunction() {
let string = self.string
print(string)
}
}
我在某个时候分配:
let variable: Void -> Void = exampleInstance.someFunction
exampleInstance.emptyBlock = variable
我是否有一个保留周期,因为variable 从someFunction 捕获exampleInstance 并且variable 被exampleInstance 保留?或者是否有某种魔法使这不成问题?
【问题讨论】:
标签:
swift
closures
block
reference-counting
【解决方案1】:
我做了一个快速测试,我相信我已经确认它们实际上被强烈捕获为可疑。我会将我的发现发布给其他有此问题的人:
上这堂课,断点在deinit:
class Example {
var emptyBlock: (Void -> Void)?
var string: String = "Here's some string"
func someFunction() {
let string = self.string
print(string)
}
deinit {
print("I was deinitialized") // Breakpoint Here
}
}
然后运行这两个示例代码:
参考循环
由于无法取消初始化而不会命中断点:
let exampleInstance = Example()
let variable = exampleInstance.someFunction
exampleInstance.emptyBlock = variable
非参考循环
会因为每周捕获而命中断点:
let exampleInstance = Example()
let variable: Void -> Void = { [weak exampleInstance] in exampleInstance?.someFunction() }
exampleInstance.emptyBlock = variable
因为当我们弱捕获时它会到达断点,我们可以有把握地得出结论,如果没有它,它就会像闭包一样被强捕获。
在使用这个工具时应该考虑到这一点,因为我们在声明闭包时不会获得相同的捕获显而易见性。没有明确的警告可以调用self 来提醒我们,并且在它们的范围内没有弱声明。
指南
我还在指南中找到了参考:
- 全局函数是具有名称但不捕获任何值的闭包。
- 嵌套函数是具有名称的闭包,可以从其封闭函数中捕获值。
- 闭包表达式是用轻量级语法编写的未命名闭包,可以从周围的上下文中捕获值。
【解决方案2】:
是的,有一个保留周期。给局部变量赋值,然后再赋值给其他变量,与直接赋值是一样的。所以该代码相当于
exampleInstance.emptyBlock = exampleInstance.someFunction
而exampleInstance.someFunction 只是语法糖
{ x in exampleInstance.someFunction(x) }