我们是否需要在Swift关闭中明确使用捕获列表?
我对关闭的理解是,它将捕获所有直接引用的对象,无论对象变量是否被声明 strong 在关闭外,如果我们想要要弱捕获它们,然后我们需要明确定义捕获列表,并在该捕获列表中标记它们。
obj?.callback = { [weak obj] in
obj?.perform()
}
但是,在我的测试中,我发现,如果该变量已经弱
在闭合外,那么我们就不需要使用捕获列表来弱捕获它。
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"
以上片段没有创建任何保留周期。这是否意味着我们不需要在捕获列表中明确捕获对象变量,如果该变量已经声明为弱
,而捕获列表仅提供句法优势,而不是创建>在使用闭合之前,可变。
My understanding for closure was, it will capture all directly referenced objects strongly irrespective of whether the object variable was declared weak
or strong
outside the closure and, if we want to capture them weakly, then we need to explicitly define a capture list and mark them weak
in that capture list.
obj?.callback = { [weak obj] in
obj?.perform()
}
However in my test, I found that if the variable is already weak
outside the closure, then we don't need to use capture list to capture it weakly.
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"
The above snippet is not creating any retain cycle. Does this mean we don't need to explicitly capture an object variable weakly in capture list if the variable is already declared weak
and capture list just provides syntactical advantage over creating a weak
variable before using them inside closure.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在这个特定的例子中,是这样的,但是你需要非常小心地思考如何看待正在发生的事情。
首先,是的,这是相同的。我们可以通过生成 SIL (
swiftc -emit-sil main.swift
) 来判断这一点。除了self
与weakSelf
的名称不同之外,它们生成完全相同的未优化 SIL。为了使它更清楚,我将更改捕获列表中变量的名称(这只是重命名,它不会改变行为):weakSelfweak_self
除了
比较它们
用户评论的顺序之外
self
,它们是相同的。但使用这些知识时要非常非常小心。这碰巧是正确的,因为在其他地方存在对
self
的强引用。在这条路上走得太远可能会导致混乱。例如,考虑以下两种方法:它们的行为根本不同。在第一个版本中,
weakObject
在创建callback
时已被释放,因此callback()
不执行任何操作。编译器将生成有关此问题的警告,因此在大多数情况下,这不太可能创建,但作为规则,您通常应该在捕获列表中进行弱捕获,以便它尽可能接近闭包创建发生,并赢得胜利不小心意外地被释放。Sort of, in this specific example, but you need to be very careful about how you think about what's happening.
First, yes, this is identical. We can tell that by generating the SIL (
swiftc -emit-sil main.swift
). Except for the difference in the name ofself
vsweakSelf
, these generate exactly the same unoptimized SIL. In order to make it even clearer, I'll change the name of the variable in the capture list (this is just a renaming, it doesn't change the behavior):weakSelf
weak_self
Compare them
Except for the order of the users comment for
self
, they're identical.But be very, very careful with what you do with this knowledge. This happens to be true because there exists a strong reference to
self
elsewhere. Going down this road too far can lead to confusion. For example, consider these two approaches:These do not behave the same at all. In the first version,
weakObject
is already released by the timecallback
is created, socallback()
does nothing. The compiler will generate a warning about this, so in most cases this is an unlikely bug to create, but as a rule you should generally do weak captures in the capture list so that it occurs as close to the closure creation as possible, and won't accidentally be released unexpectedly.