[英]Closure recursion and retain cycles
我的关闭保留了它自己。 它会导致捕获内部的所有其他对象。 我可以使用弱引用传递这样的对象,但它并不能解决保留循环的问题。 在没有保留周期的情况下使用闭包进行递归的正确方法是什么?
class Foo {
var s = "Bar"
deinit {
print("deinit") // Won't be executed!
}
}
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo() // Weak works, but not the right solution.
var closure: () -> Void = { return }
closure = {
print(foo.s)
if true {
return
} else {
closure()
}
}
}
}
你有一个不寻常的设置,你的闭包保留了它自己。 请注意,Swift 不允许您创建对闭包的弱引用。
要中断保留循环,请在递归的基本情况下将closure
设置为{ }
。 这是一个测试 macOS 命令行程序:
func test() {
var closure: ((Int) -> ()) = { _ in }
closure = { i in
if i < 10 {
closure(i + 1)
} else {
// Comment out this line for unbounded memory consumption.
closure = { _ in }
}
}
closure(0)
}
while true {
test()
}
如果你运行它,它的内存消耗是平的。
如果您注释掉重置closure
的基本情况中的行,则其内存消耗会无限制地增长。
您的closure
持有foo
实例引用。 foo
将在closure
释放后立即释放。
closure
在呼唤自己。 如果我们在closure
传递弱self
,那应该没问题。 或通过重置closure
下面的代码应该可以正常工作。
var closure: () -> Void = { return }
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
closure = { [weak self] in
print(foo.s)
if true {
return
} else {
self?.closure()
}
}
}
或在closure
内初始化foo
override func viewDidLoad() {
super.viewDidLoad()
var closure: () -> Void = { return }
closure = { [weak self] in
let foo = Foo()
print(foo.s)
if true {
return
} else {
self?.closure()
}
}
}
把你的闭包变成一个嵌套函数:
class Foo {
var s = "Bar"
deinit {
print("deinit")
}
}
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
func nestedFunction() {
print(foo.s)
if true {
return
} else {
nestedFunction()
}
}
nestedFunction()
}
}
在 Swift 中,嵌套函数可以同步(递归函数)或异步(通常用于异步迭代)引用自己,可以在没有任何引用循环的情况下这样做,并且可以像闭包一样捕获变量。 你甚至可以有相互递归的嵌套函数。
您可以改为在完成后将包含闭包的变量重置为虚拟闭包,我并不是说这不起作用,但这很容易出错,尤其是当闭包异步调用自身时:重置也必须异步完成在这种情况下。 最好静态地确保没有引用循环,这在 Swift 中的大多数其他地方都可以做到。
(由于 gcc 在 C 语言中的实现,由于试图将闭包引用压缩到 C 函数指针(即代码地址)中而引入了安全漏洞,因此这个概念曾经有一个不好的说唱,但 Swift 嵌套函数没有什么可这样做)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.