If all the strong
references to an instance are removed, then the instance will eventually be deallocated. But that doesn't necessarily mean the references that were referring to it will be reused. All the strong
references are obviously gone because they had to be in order for it to be deallocated in the first place. So whatever that means for the memory that those references required for their referring duties is irrelevant to the application, because the references don't exist anywhere in it anymore.
Which leaves unowned
and weak
references left. Apple makes it pretty clear that attempting to access the value of an unowned
reference after the instance has been deallocated is a no, no:
If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.
So that is also irrelevant to the application, simply because it's a hard-rule not to be broken.
Which leaves, last but not least, weak
references. Apple says this about weak references:
Because a weak reference does not keep a strong hold on the instance
it refers to, it’s possible for that instance to be deallocated while
the weak reference is still referring to it. Therefore, ARC
automatically sets a weak reference to nil when the instance that it
refers to is deallocated.
...
You can check for the existence of a value in the weak reference, just
like any other optional value, and you will never end up with a
reference to an invalid instance that no longer exists.
The key take away here is that the reference is set to nil
. And even though nil
represents nothing, it's still a valid value. And I feel it may be safe to assume that the runtime environment won't steal a reference and use it for another purpose when it's still pointing to a valid value. Imagine what it'd be like otherwise.
So the relevance to the application here for weak
references is just that they may become nil
at some point; and as @MartinR showed in his answer, this may even happen mid-execution of the closure. So the final solution would seem to be creating a strong
reference from the weak
reference before using it, aka the "weak/strong dance":
Either:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
or
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
}
If the closure consists of a single optional chain:
{ [weak self] in
self?.doSomething()
}
will simply result in a non-op if self
is nil
, but no idea if this bears any guarantee that self
won't be deallocated mid-execution of the closure if it's arbitrarily longer:
{ [weak self] in
self?.doSomething()
...
self?.doSomethingDownTheLine()
}
So in this case, doing the weak/strong dance will guarantee that your closure will be all-or-nothing:
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
...
strongSelf.doSomethingDownTheLine()
}