🎓 A1Learner
🔍
0 of 27 lessons completed

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 = nil

Two 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 = nil

A 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 = nil

An 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 = nil

Example

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 = nil

Key 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?