Swift Unowned References
An unowned reference points to a class instance without keeping that instance alive. It is used when the owner is expected to outlive the object that holds the reference.
A tool that refers to its owner
The Tool class holds its Owner with an unowned reference. The label reads the name through that reference while a strong reference keeps the owner alive, and releasing that strong reference then runs the deinitializer of the owner.
class Owner {
var name: String
init(name: String) {
self.name = name
}
deinit {
print("Owner gone")
}
}
class Tool {
unowned let owner: Owner
init(owner: Owner) {
self.owner = owner
}
func label() -> String {
return "Tool for \(owner.name)"
}
}
var owner: Owner? = Owner(name: "Ana")
let tool = Tool(owner: owner!)
print(tool.label())
owner = nilTwo tools share one owner
The Hammer tool and the Saw tool each hold the same owner with an unowned reference. Both labels read the owner name, and the owner deinitializer runs once when the strong reference is released.
class Owner {
var name: String
init(name: String) {
self.name = name
}
deinit {
print("Owner gone")
}
}
class Tool {
unowned let owner: Owner
var toolName: String
init(owner: Owner, toolName: String) {
self.owner = owner
self.toolName = toolName
}
func label() -> String {
return "\(toolName) for \(owner.name)"
}
}
var owner: Owner? = Owner(name: "Ana")
let hammer = Tool(owner: owner!, toolName: "Hammer")
let saw = Tool(owner: owner!, toolName: "Saw")
print(hammer.label())
print(saw.label())
owner = nilA card that refers back to its customer
The Customer class holds its Card with a strong reference, and the Card class holds its customer with an unowned reference. Releasing the customer therefore releases both objects, and each deinitializer prints its line.
class Customer {
var name: String
var card: Card?
init(name: String) {
self.name = name
}
deinit {
print("Customer gone")
}
}
class Card {
unowned let customer: Customer
var number: Int
init(customer: Customer, number: Int) {
self.customer = customer
self.number = number
}
deinit {
print("Card gone")
}
}
var customer: Customer? = Customer(name: "Bo")
customer!.card = Card(customer: customer!, number: 123)
if let card = customer!.card {
print(card.customer.name)
print(card.number)
}
customer = nilAn unowned reference does not keep the owner alive
Two strong references point to the same owner at the start of this program. Clearing the first one leaves the owner alive through the second one, and clearing the second one runs the deinitializer of the owner.
class Owner {
var name: String
init(name: String) {
self.name = name
}
deinit {
print("Owner gone")
}
}
class Tool {
unowned let owner: Owner
init(owner: Owner) {
self.owner = owner
}
func label() -> String {
return "Tool for \(owner.name)"
}
}
var first: Owner? = Owner(name: "Cy")
var second: Owner? = first
let tool = Tool(owner: first!)
first = nil
print(tool.label())
second = nilExample
class Customer {
var name: String
var card: Card?
init(name: String) {
self.name = name
}
deinit {
print("Customer gone")
}
}
class Card {
unowned let customer: Customer
var number: Int
init(customer: Customer, number: Int) {
self.customer = customer
self.number = number
}
deinit {
print("Card gone")
}
}
var customer: Customer? = Customer(name: "Dana")
customer!.card = Card(customer: customer!, number: 456)
if let card = customer!.card {
print(card.customer.name)
print(card.number)
}
customer = nilKey points
- An unowned reference is declared with the unowned keyword before the property name.
- Unlike a weak reference, an unowned reference is not an optional and does not become nil.
- An unowned reference does not add to the strong references that keep its owner alive.
- Releasing the last strong reference to an owner still runs the deinitializer of that owner.
- An unowned reference must only be read while its owner is still alive.
In this example, a Customer named Dana holds a Card with the number 456, and the card refers back to the customer with an unowned reference. The prints show Dana and 456 while the customer is alive. Clearing the customer then prints Customer gone and Card gone as both objects are released.
Note
Two objects can avoid a strong cycle when one side holds the other strongly and the back reference is unowned.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does an unowned reference do to the lifetime of the instance it points to?