Swift 为嵌套回调保护弱自我

Dev*_*don 6 callback swift

我的问题更像是更好的答案练习。假设我们有回调的多个嵌套层,每一个我们有层做出selfweak和我知道我们可以写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这里是引用当前类(可能是模型,可能是视图控制器),可以在三个回调中的任何一个发生期间释放/弹出。

Dev*_*don 8

我认为@Andriy 的回答中的大部分内容是正确的。但最正确的答案是我们甚至不需要放入[weak self]任何嵌套块。

当我第一次从同事那里听到这个时,我不想买它。但事实是,在第一块定义了捕捉 selfweak这拍摄的自我将影响所有当前范围内捕获的自我,换句话说,内第一块的{}。因此,[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并且被正确调用。