我对闭包的理解是,它会强烈地捕获所有直接引用的对象,而不管对象变量是声明的weak
还是strong
在闭包之外,如果我们想弱捕获它们,那么我们需要显式定义一个捕获列表并weak
在其中标记它们捕获列表。
obj?.callback = { [weak obj] in
obj?.perform()
}
但是在我的测试中,我发现如果变量已经weak
在闭包之外,那么我们就不需要使用捕获列表来弱捕获它了。
class Foo {
var callback: (() -> ())?
init() {
weak var weakSelf = self
callback = {
weakSelf?.perform()
}
// is above equivalent to below in terms of memory management?
// callback = { [weak self] in
// self?.perform()
// }
}
func perform() {
print("perform")
}
deinit {
print("deinit")
}
}
let foo = Foo() // prints "deinit foo"
上面的代码段没有创建任何保留周期。这是否意味着如果变量已经声明,我们不需要在捕获列表中显式地捕获对象变量,weak
并且捕获列表只是在语法上优于weak
在闭包中使用它们之前创建变量。
有点,在这个具体的例子中,但你需要非常小心你如何看待正在发生的事情。
首先,是的,这是相同的。我们可以通过生成 SIL ( swiftc -emit-sil main.swift
) 来判断这一点。除了self
vs的名称不同外weakSelf
,它们生成完全相同的未优化 SIL。为了更清楚,我将更改捕获列表中变量的名称(这只是重命名,不会改变行为):
weak var weakSelf = self
callback = {
weakSelf?.perform()
}
callback = { [weak weakSelf = self] in
weakSelf?.perform()
}
$ swiftc -emit-sil weakSelf.swift > weakSelf.sil
$ swiftc -emit-sil weak_self.swift > weak_self.sil
$ diff -c weakSelf.sil weak_self.sil
*** weakSelf.sil 2022-03-27 10:58:13.000000000 -0400
--- weak_self.sil 2022-03-27 11:01:22.000000000 -0400
***************
*** 102,108 ****
// Foo.init()
sil hidden @$s4main3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
! // %0 "self" // users: %15, %8, %7, %2, %22, %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Foo, #Foo.callback // user: %4
--- 102,108 ----
// Foo.init()
sil hidden @$s4main3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
! // %0 "self" // users: %8, %7, %15, %2, %22, %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Foo, #Foo.callback // user: %4
除了用户评论的顺序之外self
,它们是相同的。
但是要非常非常小心地处理这些知识。这恰好是真的,因为存在对self
其他地方的强烈引用。在这条路上走得太远会导致混乱。例如,考虑以下两种方法:
// Version 1
weak var weakObject = Object()
let callback = {
weakObject?.run()
}
callback()
// Version 2
var weakObject = Object()
let callback = { [weak weakObject] in
weakObject?.run()
}
callback()
这些行为根本不一样。在第一个版本中,weakObject
在创建时已经发布callback
,所以callback()
什么也不做。编译器会对此产生警告,因此在大多数情况下,这是一个不太可能创建的错误,但通常你应该在捕获列表中进行弱捕获,以便它尽可能接近闭包创建,并赢得不小心被意外释放。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句