一尘不染

虚弱的自我会去哪里?

swift

我经常这样做

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()
   }
}

或者,也许

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()
   }
}

我们应该做什么?

所有这三个建议 似乎都 可以正常工作。这里的完整含义是什么?那该怎么办?强引用是弱引用,弱引用还是强引用?生存还是毁灭?这就是问题所在!


阅读 290

收藏
2020-07-07

共1个答案

一尘不染

首先,请注意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

2020-07-07