In WWDC 2014 session 403 Intermediate Swift and transcript, there was the following slide
No, there are definitely times where you would not want to use [unowned self]
. Sometimes you want the closure to capture self in order to make sure that it is still around by the time the closure is called.
If you are making an asynchronous network request you do want the closure to retain self
for when the request finishes. That object may have otherwise been deallocated but you still want to be able to handle the request finishing.
unowned self
or weak self
The only time where you really want to use [unowned self]
or [weak self]
is when you would create a strong reference cycle. A strong reference cycle is when there is a loop of ownership where objects end up owning each other (maybe through a third party) and therefore they will never be deallocated because they are both ensuring that each other stick around.
In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the [unowned self]
or [weak self]
. So if a class owns a closure, and that closure captures a strong reference to that class, then you have a strong reference cycle between the closure and the class. This also includes if the class owns something that owns the closure.
In the example on the slide, TempNotifier
owns the closure through the onChange
member variable. If they did not declare self
as unowned
, the closure would also own self
creating a strong reference cycle.
unowned
and weak
The difference between unowned
and weak
is that weak
is declared as an Optional while unowned
is not. By declaring it weak
you get to handle the case that it might be nil inside the closure at some point. If you try to access an unowned
variable that happens to be nil, it will crash the whole program. So only use unowned
when you are positive that variable will always be around while the closure is around
Here is brilliant quotes from Apple Developer Forums described delicious details:
unowned
vs unowned(safe)
vs unowned(unsafe)
unowned(safe)
is a non-owning reference that asserts on access that the object is still alive. It's sort of like a weak optional reference that's implicitly unwrapped withx!
every time it's accessed.unowned(unsafe)
is like__unsafe_unretained
in ARC—it's a non-owning reference, but there's no runtime check that the object is still alive on access, so dangling references will reach into garbage memory.unowned
is always a synonym forunowned(safe)
currently, but the intent is that it will be optimized tounowned(unsafe)
in-Ofast
builds when runtime checks are disabled.
unowned
vs weak
unowned
actually uses a much simpler implementation thanweak
. Native Swift objects carry two reference counts, andunowned
references bump the unowned reference count instead of the strong reference count. The object is deinitialized when its strong reference count reaches zero, but it isn't actually deallocated until the unowned reference count also hits zero. This causes the memory to be held onto slightly longer when there are unowned references, but that isn't usually a problem whenunowned
is used because the related objects should have near-equal lifetimes anyway, and it's much simpler and lower-overhead than the side-table based implementation used for zeroing weak references.
Update: In modern Swift weak internally uses the same mechanism as unowned does. So this comparison is incorrect because it compares Objective-C weak
with Swift unonwed
.
What is the purpose of keeping the memory alive after owning references reach 0? What happens if code attempts to do something with the object using an unowned reference after it is deinitialized?
The memory is kept alive so that its retain counts are still available. This way, when someone attempts to retain a strong reference to the unowned object, the runtime can check that the strong reference count is greater than zero in order to ensure that it is safe to retain the object.
What happens to owning or unowned references held by the object? Is their lifetime decoupled from the object when it is deinitialized or is their memory also retained until the object is deallocated after the last unowned reference is released?
All resources owned by the object are released as soon as the object's last strong reference is released, and its deinit is run. Unowned references only keep the memory alive—aside from the header with the reference counts, its contents is junk.
Excited, huh?
If self could be nil in the closure use [weak self].
If self will never be nil in the closure use [unowned self].
The Apple Swift documentation has a great section with images explaining the difference between using strong, weak, and unowned in closures:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html