Unowned Properties in Swift
It's very common to use the weak
keyword in order to prevent reference cycles in properties like delegates:
weak var delegate: HomeViewDelegate?
Unfortunately, since it protects you from references being lost, the weak
keyword forces the usage of var
and an optional type, which can be quite jarring if you're building something like an UIView
that is not supposed to be used without a delegate - much less change delegates suddenly:
class HomeView: UIView {
weak var delegate: HomeViewDelegate?
func renderView() {
guard let delegate = delegate else {
//Timmy: this should never happen!
return
}
let category = delegate.currentlySelectedCategory()
categoryView.render(category: category)
delegate.homeViewDidUpdate()
}
}
But weak
is not the only way of breaking reference cycles. Just like in capture lists, the unowned
keyword can be used in properties to create non-strong references:
unowned let delegate: HomeViewModelDelegate
Unlike weak
, unowned
references are expected to always have a value. This allows you to not only use non-optional types when declaring them, but also to do so with let
, bringing back immutability and making sure your objects won't act in unexpected ways:
class HomeView: UIView {
private unowned let delegate: HomeViewDelegate
init(delegate: HomeViewDelegate) {
self.delegate = delegate
super.init(frame: .zero)
}
func renderView() {
let category = delegate.currentlySelectedCategory()
categoryView.render(category: category)
delegate.homeViewDidUpdate()
}
}
With weak
, there's nothing stopping HomeView
from being used without a delegate, and a guard
is required to unwrap values retrieved from the delegate due to the optional requirement of the keyword. On the other hand, unowned
allows you to break reference cycles while still using the reference just like if it was strong.
However, be aware that unowned
properties will work just like the capture list keyword. If you try to access an unowned reference that has already deallocated, your app will crash.
If your object is guaranteed to never outlive its unowned reference (like a ViewModel
, for example), usage of unowned
can greatly improve both code quality and performance.
But unowned
can crash your app just like implicitly unwrapped optionals. Shouldn't you use weak
for everything?
Most people rely on weak
for everything and frown upon unowned
due to its potential crashes, specially on capture lists. This is a safe way to use Swift, but not Apple's intended practice.
Unlike implicitly unwrapped optionals, which in my opinion are just a lazy way of overcoming architectural problems, unowned
references have significant advantages over weak
ones: They have better performance, allow immutability, and since they can't be manually set to nil
, your code will not accidentally follow unexpected paths. unowned
references are perfectly safe - problems will only arise if you misuse the keyword.
According to Apple, you should always use unowned
references when your object can't outlive its reference:
Use an unowned reference only when you are sure that the reference always refers to an instance that has not been deallocated.
If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.
If the captured reference will never become nil, it should always be captured as an unowned reference, rather than a weak reference.
In any other cases, you should keep using weak
references.
What else?
The next time you create a delegate or an @escaping
closure, think about its context and see if it's possible for it to outlive its reference. If it doesn't, you might find unowned
properties an interesting tool to improve your code's quality.
Follow me on my Twitter - @rockbruno_, and let me know of any suggestions and corrections you want to share.