弱者自己去哪儿了?

时间:2017-02-01 23:03:47

标签: swift weak-references

我经常这样做,

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
   beep()
}

在一个应用程序中我们经常这样做

tickle.fresh(){
    msg in
    paint()
}

但是如果你这个

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
   tickle.fresh(){
      msg in
      paint()
   }
}

当然你必须做这个

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
   tickle.fresh(){
      msg in
      self?.paint()
   }
}

或者, this

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
   tickle.fresh(){
      [weak self] msg in
      self?.paint()
   }
}

或者这个

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
   tickle.fresh(){
      [weak self] msg in
      self?.paint()
   }
}

我们应该做什么?

所有三个建议似乎才能完美运作。这里意义的深度是什么?一个人应该做什么?强引用弱引用,弱引用还是强引用?生存还是毁灭?这是个问题!

1 个答案:

答案 0 :(得分:88)

首先,请注意,您通常不需要担心DispatchQueue.main.asyncAfter的保留周期,因为闭包将在某些点执行。因此,无论您是否轻微捕获self,您都不会创建永久保留周期(假设tickle.fresh也没有)。

是否在外部[weak self]闭包上放置asyncAfter捕获列表完全取决于您是否希望在调用闭包之前保留self(在您设置的时间之后) )。如果您在调用关闭之前不需要self保持活着,请将[weak self]放入,如果您这样做,则不要将其放入。

你是否在内部闭包上放置[weak self](传递给tickle.fresh的那个)取决于你是否已经在外部闭包中弱化了self。如果你没有,那么你可以放[weak self]以防止内封闭保留它。但是,如果外部闭包已经弱捕获self,则内部闭包已经self具有弱引用,从而将[weak self]添加到内部关闭将无效。

所以,总结一下:

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
   tickle.fresh { msg in
      self.paint()
   }
}

self将由外部和内部闭合保留。

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
   tickle.fresh { msg in
      self?.paint()
   }
}
任何一个闭包都不会保留

self

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
   tickle.fresh { [weak self] msg in
      self?.paint()
   }
}

与上面相同,内部闭包的附加[weak self]没有效果,因为外部闭包已经弱地捕获了self

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
   tickle.fresh { [weak self] msg in
      self?.paint()
   }
}

self将被外部闭包保留,但不会被内部闭合保留。

当然,可能是您不希望外部闭包保留self,但是希望内部闭包保留它。在这种情况下,您可以在外部闭包中声明一个局部变量,以便保留对self的强引用,然后您可以在内部闭包中捕获:

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
   guard let strongSelf = self else { return }
   tickle.fresh { msg in
      strongSelf.paint()
   }
}

现在,self不会被外部封闭所保持活着,但是一旦它被调用,如果self仍然存在,它将由内部封闭保持活着直到关闭已被解除分配。

回应:

  

强引用弱引用,弱引用还是强引用?

弱引用作为选项实现,它们是值类型。因此,你不能直接有一个强引用 - 而是你首先必须打开它,然后对底层实例进行强引用。在这种情况下,您只需处理强引用(与我上面的strongSelf示例完全相同)。

但是,如果弱引用是盒装(这种情况发生在闭包捕获 - 值类型将被放入堆分配的盒子中) - 那么你确实可以对该盒子有一个强引用。这种效果相当于对原始实例的弱引用,你只需要一个不可见的额外间接位。

实际上,这是完全在外部闭包弱捕获self并且内部闭合强烈捕获'的示例中发生的情况。那个弱的参考。结果是两个闭包都没有保留self