【问题标题】:Is it the right way using `[weak self]` in swift closure?在快速关闭中使用 `[weak self]` 是正确的方法吗?
【发布时间】:2019-02-16 02:05:00
【问题描述】:

我总是在快速关闭时使用[weak self] 来防止引用循环。 这是下面的代码,它是正确的方法吗?

someTask(completion: {[weak self] (result) in
        if self == nil {  
            return
        }

        //is it safe when reach here? 

        self!.xxx = yyy
        self!.doLongTermWork()
        self!.finish()  //will crash when self is nil?
    })

弱自我不会对实例保持强控制。那么当self.doLongTermWork() 时,self 会在其他地方再次设置为nil 吗?

【问题讨论】:

    标签: swift closures weak


    【解决方案1】:

    你的模式有竞争条件。如果 self 在完成处理程序闭包执行的同时被释放,它可能会崩溃。作为一般规则,如果可以,请避免使用 ! 强制展开运算符。

    1. 我倾向于guard“提前退出”模式(减少嵌套括号,使代码更易于阅读)。标准的 Swift 4.2 解决方案是:

      someTask { [weak self] result in
          guard let self = self else { return }
      
          self.xxx = yyy
          self.doLongTermWork()
          self.finish()
      }
      
    2. 在实现 SE-0079 的 Swift 4.2 之前,我们必须执行以下操作:

      someTask { [weak self] result in
          guard let strongSelf = self else { return }
      
          strongSelf.xxx = yyy
          strongSelf.doLongTermWork()
          strongSelf.finish()
      }
      

      您可以看到为什么我们更喜欢 Swift 4.2 的改进,因为这种 strongSelf 语法不优雅。

    3. 另一个明显的选择是:

      someTask { [weak self] result in
          self?.xxx = yyy
          self?.doLongTermWork()
          self?.finish()
      }
      

      有时你需要“弱自强自舞”(前两种选择),但这里似乎不是这样。这可能就足够了。

    人们可能会考虑其他场景/边缘情况,但这些是基本方法。

    【讨论】:

      【解决方案2】:

      你说:

      someTask(completion: {[weak self] (result) in
          if self == nil {  
              return
          }
          //is it safe when reach here? 
          self!.xxx = yyy
      })
      

      不!你还没有保留self,所以理论上它可能在闭包执行期间的任何时候变成nil。它可能不会,但“可能”还不够好。感叹号总是会导致崩溃。

      跳弱强舞,并正确地跳:

      someTask(completion: {[weak self] (result) in
          if let self = self {  // or let `self` before Swift 4
              // here, self is safe, because you made the reference strong again
              self.xxx = yyy
          }
      })
      

      【讨论】:

      • 为什么不简单的可选链呢?
      【解决方案3】:

      你可以在 Swift 4.2 中这样使用它

      someTask(completion: {[weak self] (result) in
          guard let self = self { return }
      
          //it safe when reach here always
      
          self.xxx = yyy
          self.doLongTermWork()
          self.finish()
      })
      

      【讨论】:

      • 谢谢。但我还有另一个困惑。当我想一次弱化多个对象时,例如:{[weak self], [weak obj1], [weak obj2].. in ...}。防止竞争条件是否线程安全。
      • @JamesZhang - 语法为someTask { [weak self, weak obj1, weak obj2] in ... }。是的,你可以这样做,但在实践中,你需要这样做是非常罕见的。你必须给我们一个实际的例子,说明你打算什么时候这样做。但是这些weak 捕获引用是为了避免强引用循环和竞争条件:它绝不是线程安全的任何保证。这是一个不同的、更广泛的话题。
      猜你喜欢
      • 1970-01-01
      • 2015-07-02
      • 2016-05-02
      • 2021-12-11
      • 2015-10-12
      • 2017-01-09
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      相关资源
      最近更新 更多