I have got an interview question about unowned
recently. While I can answer it correctly, I was struggling a bit when the interviewer asked me examples when I should use unowned
, because I’d rather answer: NEVER 😁. I rarely use unowned
in my projects, but it’s worth it to understand why the keyword exists and when to use it.
What is unowned
?
The unowned
keyword is used to define a weak reference to an object in Swift. Unlike a strong reference, which keeps an object alive as long as there is at least one reference to it, an unowned
reference does not increase the retain count of the object it refers to. This means that an unowned
reference does not prevent the referenced object from being deallocated.
When you declare a property as unowned
, you are essentially telling the compiler that you are certain that the referenced object will not be deallocated before the referencing object. If you try to access an unowned
reference after the referenced object has been deallocated, your app will crash with a fatal error.
Generally, unowned
referencing is faster than weak
referencing because the compiler doesn’t need to add extract code for ARC, and the apps don’t need to execute those extra code in runtime.
When to use unowned references?
Breaking Retain Cycles:
One common scenario where unowned
is used is to break retain cycles between objects. A retain cycle occurs when two or more objects hold strong references to each other, preventing them from being deallocated even when they are no longer needed. By using unowned
, you can break the retain cycle and allow the objects to be deallocated properly.
Example:
class Person {
var name: String
var car: Car?
init(name: String) {
self.name = name
}
deinit {
print("\(name) is being deinitialized")
}
}
class Car {
var model: String
unowned var owner: Person
init(model: String, owner: Person) {
self.model = model
self.owner = owner
}
deinit {
print("Car \(model) is being deinitialized")
}
}
In this example, a Person
can own a Car
, and a Car
has an unowned reference to its owner
. This prevents a retain cycle between the Person
and Car
instances.
Parent-Child Relationships:
Another situation where unowned
is applicable is when you have a parent-child relationship between objects, and you are certain that the parent object will always outlive the child object.
Example:
class Parent {
var child: Child?
deinit {
print("Parent is being deinitialized")
}
}
class Child {
unowned var parent: Parent
init(parent: Parent) {
self.parent = parent
}
deinit {
print("Child is being deinitialized")
}
}
In this case, a Child
object always has a parent, and the parent
property is declared as unowned
because the Parent
object is expected to outlive the Child
object.
Important Considerations
- Use
unowned
only when you are absolutely sure that the referenced object will not be deallocated before the referencing object. If you have any doubts, consider usingweak
instead. - Accessing an
unowned
reference after the referenced object has been deallocated will result in a runtime crash. Make sure to handle the lifecycle of objects correctly. - If the referenced object can be
nil
at some point, useweak
instead ofunowned
to avoid crashes.
Conclusion
The unowned
keyword in Swift is a powerful tool for managing object relationships and preventing retain cycles. By using unowned
, you can define weak references to objects and ensure proper memory management. However, it’s important to use unowned
carefully and only when you are certain about the lifecycle of the referenced objects. Understanding when and how to use unowned
can help you write more efficient and robust Swift code.