I often do this,
let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { beep() }
and in one app we often do this
tickle.fresh(){ msg in paint() }
but if you do this
let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { tickle.fresh(){ msg in paint() } }
of course you have to do this
let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in tickle.fresh(){ msg in self?.paint() } }
or, maybe this
let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { tickle.fresh(){ [weak self] msg in self?.paint() } }
or maybe this
let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in tickle.fresh(){ [weak self] msg in self?.paint() } }
All three suggestions seem to work perfectly. What's the full depth of meaning here? And which should one do? Is a strong reference to a weak reference, a weak or strong reference? To be or not to be? That's the question!
In Swift, [weak self] prevents closures from causing memory leaks in your application. This is because when you use [weak self], you tell the compiler to create a weak reference to self. In other words, the ARC can release self from memory when necessary.
The answer is NO. First of all [weak self] is only required for escaping closures that capture self . Escaping closures is just a fancy name for closures that get stored and do not get executed immediately, unlike the non-escaping ones.
According to Apple's docs: “Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialisation.”
Unowned references are similar to weak references in that they don't keep a strong reference to the instance they are referencing. They serve the same purpose as weak references, that is, they avoid strong reference cycles.
First of all, note that you generally don't need to worry about retain cycles with DispatchQueue.main.asyncAfter
, as the closure will be executed at some point. Therefore whether or not you weakly capture self
, you won't be creating a permanent retain cycle (assuming that tickle.fresh
also doesn't).
Whether or not you put a [weak self]
capture list on the outer asyncAfter
closure depends entirely on whether you want self
to be retained until the closure is called (after the time you set). If you don't need self
to remain alive until the closure is called, put [weak self]
in, if you do, then don't put it in.
Whether or not you put a [weak self]
on the inner closure (the one passed to tickle.fresh
) depends on whether you've already weakly captured self
in the outer closure. If you haven't, then you can put [weak self]
in order to prevent the inner closure from retaining it. If however, the outer closure has already weakly captured self
, then the inner closure will already have a weak reference to self
, thus adding [weak self]
to the inner closure will have no effect.
So, to summarise:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { tickle.fresh { msg in self.paint() } }
self
will be retained by both the outer and inner closure.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in tickle.fresh { msg in self?.paint() } }
self
will not be retained by either closure.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in tickle.fresh { [weak self] msg in self?.paint() } }
Same as the above, the additional [weak self]
for the inner closure has no effect, as self
is already weakly captured by the outer closure.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { tickle.fresh { [weak self] msg in self?.paint() } }
self
will be retained by the outer closure, but not the inner closure.
Of course, it might be that you don't want self
to be retained by the outer closure, but you do want it to be retained by the inner closure. In such cases, you can declare a local variable in the outer closure in order to hold a strong reference to self
, when you can then capture in the inner closure:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in guard let strongSelf = self else { return } tickle.fresh { msg in strongSelf.paint() } }
Now, self
won't be kept alive by the outer closure, but once it's called, if self
still exists, it will be kept alive by the inner closure until that closure has been deallocated.
In response to:
Is a strong reference to a weak reference, a weak or strong reference?
Weak references are implemented as optionals, which are value types. Therefore you cannot directly have a strong reference to one – instead you first have to unwrap it, and then take a strong reference to the underlying instance. In this case you're simply dealing with a strong reference (exactly like my example above with strongSelf
).
However, if a weak reference is boxed (this happens with closure capture – the value type will be put into a heap-allocated box) – then you can indeed have a strong reference to that box. The effect of this is equivalent to a weak reference to the original instance, you just have an invisible bit of extra indirection.
In fact, this is exactly what happens in the example where the outer closure weakly captures self
and the inner closure 'strongly captures' that weak reference. The effect is that neither closure retains self
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With