我的问题更像是更好的答案练习。假设我们有回调的多个嵌套层,每一个我们有层做出self要weak和我知道我们可以写guard为每一层(见代码片段),但是这甚至是必要的?如果我们只在第一层守卫是否足够(见代码片段2)?
如果我们从引用计数的角度考虑,第一个strongself就够了吗?
片段 1:
let callBack1 = { [weak self] xx in
guard let strongSelf = self { return }
// strongSelf.func(param)
let callBack2 = { [weak self] yy in {
guard let strongSelf = self { return }
// strongSelf.func(param)
let callBack3 = { [weak self] zz in
guard let strongSelf = self { return }
// strongSelf.func(param)
}
}
}
Run Code Online (Sandbox Code Playgroud)
片段 2:
let callBack1 = { [weak self] xx in
guard let strongSelf = self { return }
// strongSelf.func(param)
let callBack2 = { [weak self] yy in {
// strongSelf.func(param)
let callBack3 = { [weak self] zz in
// strongSelf.func(param)
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:这是我们代码库中的合法案例,不要假设这永远不会发生。
编辑:为了澄清这个问题,我们假设每个回调都是异步发生的,self这里是引用当前类(可能是模型,可能是视图控制器),可以在三个回调中的任何一个发生期间释放/弹出。
我认为@Andriy 的回答中的大部分内容是正确的。但最正确的答案是我们甚至不需要放入[weak self]任何嵌套块。
当我第一次从同事那里听到这个时,我不想买它。但事实是,在第一块定义了捕捉 self是weak这拍摄的自我将影响所有当前范围内捕获的自我,换句话说,内第一块的{}。因此,[weak self]如果我们在最第一层回调中完成了,则无需再申请。
很难从 Apple 找到确切的文档来证明这一点,但以下带有核心基础的代码片段保留计数CFGetRetainCount()可以证明这是真的。
class TestClass {
var name = ""
var block1: (()->Void)?
var block2: (()->Void)?
func test() {
print(CFGetRetainCount(self))
self.block1 = { [weak self] in
self?.block2 = { // [weak self] in
print(CFGetRetainCount(self))
}
self?.block2?()
print(CFGetRetainCount(self))
}
self.block1?()
print(CFGetRetainCount(self))
}
deinit {
print(CFGetRetainCount(self))
}
}
do {
let tstClass = TestClass()
print(CFGetRetainCount(tstClass))
tstClass.test()
print(CFGetRetainCount(tstClass))
}
Run Code Online (Sandbox Code Playgroud)
如果您有兴趣,可以在您的[weak self]Playground 中尝试此操作,随时删除for block2的评论,您将看到相同的答案。
保留计数始终为 2,deinit并且被正确调用。