在声明强自我后在闭包中使用 [弱自我] 是否有潜在的缺点?
Are there potential drawbacks to using a [weak self] within a closure after declaring a strong self?
我为此使用的标题可能不是特别清楚,所以我希望工作代码示例可以提供一些清晰度。
我面临的问题是我有一个类似于下面代码的场景:
import Foundation
class Test {
private var isInner = false {
didSet {
print("isInner: \(isInner)")
}
}
private func runClosure(closure: () -> ()) {
closure()
}
func callClosure() {
// Weak 1
runClosure { [weak self] in
self?.isInner = false
guard let strongSelf = self else { return }
// Can this [weak self] create problems?
// Weak 2
strongSelf.runClosure { [weak self] in
self?.isInner = true
}
}
}
}
let test = Test()
test.callClosure()
// The following is printed to the console
// isInner: false
// isInner: true
上面的一切都按预期工作,这很好。
我担心的是 [weak self]
的第二次使用。虽然 self
在函数开始时被声明为 weak (Weak1),但我随后不久将其设置为 strongSelf
。
我可以 re-use 我之前的 strongSelf
,但有问题的函数实际上可能是很长的 运行 操作,并且存在 self 可能超出范围的可能性 Weak1 和 Weak2。
但是,我注意到 Weak2
存在无效的可能性,这正是我希望通过这个问题澄清的。
最终,weak 所做的只是为 self 创建一个可选变量,所以我不知道有任何潜在的陷阱。此外,Weakself1、strongSelf
和Weakself2在callClosure()
执行期间都指向同一个内存地址。
让我们一步步来(逐行)
// Weak 1
runClosure { [weak self] in
第一行创建对目标对象的引用,该引用巧合地(或不巧合地)命名为 self
.
self?.isInner = false
上面一行使用了弱引用,对目标对象的生命周期没有影响。
guard let strongSelf = self else { return }
现在,这一行确实创建了对目标对象的强引用,这将至少延长对象的生命周期strongSelf
。现在,根据编译器的积极性,strongSelf
可能会在通过此行(代码中的最后一个引用)或外部闭包完成执行后死亡。
// Can this [weak self] create problems?
// Weak 2
strongSelf.runClosure { [weak self] in
现在这与从外部闭包捕获的效果几乎完全相同。它创建对可能已经释放的实例的引用(取决于此时 strongSelf
是否仍然存在)。
self?.isInner = true
这是常规的可选用法,对目标生命周期没有影响。
现在,假设 runClosure
异步运行,目标对象的寿命比预期的要长没有问题(假设那里没有更多的强引用)。
总而言之,一个对象的生命周期是由对该对象存在的强引用的数量决定的。一旦所有的强引用都被销毁,该对象将被自动释放。在您的特定场景中,内部闭包弱捕获并且已经弱引用,这不会影响目标对象的生命周期。唯一的玩家是 strongSelf
,它不迟于外部闭包销毁被销毁。
我为此使用的标题可能不是特别清楚,所以我希望工作代码示例可以提供一些清晰度。
我面临的问题是我有一个类似于下面代码的场景:
import Foundation
class Test {
private var isInner = false {
didSet {
print("isInner: \(isInner)")
}
}
private func runClosure(closure: () -> ()) {
closure()
}
func callClosure() {
// Weak 1
runClosure { [weak self] in
self?.isInner = false
guard let strongSelf = self else { return }
// Can this [weak self] create problems?
// Weak 2
strongSelf.runClosure { [weak self] in
self?.isInner = true
}
}
}
}
let test = Test()
test.callClosure()
// The following is printed to the console
// isInner: false
// isInner: true
上面的一切都按预期工作,这很好。
我担心的是 [weak self]
的第二次使用。虽然 self
在函数开始时被声明为 weak (Weak1),但我随后不久将其设置为 strongSelf
。
我可以 re-use 我之前的 strongSelf
,但有问题的函数实际上可能是很长的 运行 操作,并且存在 self 可能超出范围的可能性 Weak1 和 Weak2。
但是,我注意到 Weak2
存在无效的可能性,这正是我希望通过这个问题澄清的。
最终,weak 所做的只是为 self 创建一个可选变量,所以我不知道有任何潜在的陷阱。此外,Weakself1、strongSelf
和Weakself2在callClosure()
执行期间都指向同一个内存地址。
让我们一步步来(逐行)
// Weak 1
runClosure { [weak self] in
第一行创建对目标对象的引用,该引用巧合地(或不巧合地)命名为 self
.
self?.isInner = false
上面一行使用了弱引用,对目标对象的生命周期没有影响。
guard let strongSelf = self else { return }
现在,这一行确实创建了对目标对象的强引用,这将至少延长对象的生命周期strongSelf
。现在,根据编译器的积极性,strongSelf
可能会在通过此行(代码中的最后一个引用)或外部闭包完成执行后死亡。
// Can this [weak self] create problems?
// Weak 2
strongSelf.runClosure { [weak self] in
现在这与从外部闭包捕获的效果几乎完全相同。它创建对可能已经释放的实例的引用(取决于此时 strongSelf
是否仍然存在)。
self?.isInner = true
这是常规的可选用法,对目标生命周期没有影响。
现在,假设 runClosure
异步运行,目标对象的寿命比预期的要长没有问题(假设那里没有更多的强引用)。
总而言之,一个对象的生命周期是由对该对象存在的强引用的数量决定的。一旦所有的强引用都被销毁,该对象将被自动释放。在您的特定场景中,内部闭包弱捕获并且已经弱引用,这不会影响目标对象的生命周期。唯一的玩家是 strongSelf
,它不迟于外部闭包销毁被销毁。