Swift Strong, Weak, and Unowned References Explained

Swift uses Automatic Reference Counting (ARC) to manage the lifetime of class instances, and reference strength determines whether an object stays alive or can be released. Understanding strong, weak, and unowned references helps you avoid retain cycles, memory leaks, and crashes in everyday Swift code.

Quick answer: A strong reference keeps an object alive, a weak reference does not keep it alive and becomes nil automatically, and an unowned reference also does not keep it alive but assumes the object will always exist when used.

Difficulty: Intermediate

Helpful to know first: You'll understand this better if you know Swift classes, optionals, and how variables store references to objects.

1. What Are Strong, Weak, and Unowned References?

In Swift, a class instance is usually held by one or more references. The reference type determines how ARC treats that relationship.

  • Strong references increase the instance's reference count.
  • Weak references do not increase the reference count and must always be optional.
  • Unowned references do not increase the reference count and are used when the referenced object is guaranteed to outlive the reference.

These reference kinds matter only for class instances, because value types like struct and enum are copied rather than reference-counted.

2. Why Strong, Weak, and Unowned References Matter

Without careful reference management, two objects can keep each other alive forever. That creates a retain cycle, which means ARC cannot free the memory even when the objects are no longer needed.

These reference types help you model ownership correctly:

  • Use strong when one object truly owns another.
  • Use weak when the reference should disappear automatically if the target goes away.
  • Use unowned when the relationship is non-owning but expected to be valid for the entire time it is accessed.

This distinction is especially important in parent-child relationships, delegates, closures, and object graphs with back-references.

3. Basic Syntax

Strong references

By default, Swift class references are strong. You usually do not write anything special to make a reference strong.

Swift
class Person {
    let name: String

    init(name: String) {
        self.name = name
    }
}

var person: Person? = Person(name: "Ava")

The variable person holds a strong reference to the instance. If you set it to nil and no other strong references exist, ARC can free the object.

Weak references

A weak reference is declared with the weak keyword and must be optional.

Swift
class Employee {
    weak var manager: Manager?
}

Because weak references can become nil at any time, you must safely unwrap them before use.

Unowned references

An unowned reference is declared with the unowned keyword.

Swift
class CreditCard {
    unowned let owner: Customer

    init(owner: Customer) {
        self.owner = owner
    }
}

An unowned reference is not optional, but you must be certain it is never accessed after the referenced instance has been deallocated.

4. Step-by-Step Examples

Example 1: A simple strong reference

This example shows the default ownership behavior. The object stays alive as long as the strong reference exists.

Swift
class Book {
    let title: String

    init(title: String) {
        self.title = title
        print("Book initialized")
    }

    deinit {
        print("Book deinitialized")
    }
}

var favoriteBook: Book? = Book(title: "The Swift Way")
favoriteBook = nil
Output✓ Tested · Swift 6.4
Book initialized
Book deinitialized

When favoriteBook becomes nil, ARC releases the book because no strong references remain.

Example 2: Weak delegate pattern

Delegates are commonly held weakly so the delegate object can be released independently.

Swift
protocol DownloadManagerDelegate: AnyObject {
    func downloadManagerDidFinish()
}

class DownloadManager {
    weak var delegate: DownloadManagerDelegate?

    func finishDownload() {
        delegate?.downloadManagerDidFinish()
    }
}

Because the manager does not own its delegate, the delegate can be deallocated without creating a retain cycle.

Example 3: Parent-child relationship with unowned back-reference

When a child cannot exist meaningfully without its parent, unowned can be a good fit.

Swift
class Customer {
    let name: String
    var card: CreditCard?

    init(name: String) {
        self.name = name
    }
}

class CreditCard {
    unowned let owner: Customer

    init(owner: Customer) {
        self.owner = owner
    }
}

The card can read its owner without increasing the owner's reference count, and the relationship stays safe as long as the customer outlives the card.

Example 4: Closure capture list to avoid a cycle

Closures also capture references strongly by default. Use a capture list to change that behavior.

Swift
class TimerOwner {
    var onTick: (() -> Void)?

    func start() {
        onTick = { [weak self] in
            self?.handleTick()
        }
    }

    func handleTick() {
        print("Tick")
    }
}

The capture list prevents the closure from strongly retaining self, which avoids a retain cycle if the closure is stored on the same object.

5. Practical Use Cases

  • Use strong references for normal ownership, such as view models owning service objects or collections owning their elements.
  • Use weak references for delegates, data source callbacks, and any back-reference that should not keep an object alive.
  • Use unowned references for tightly coupled objects with a guaranteed lifetime relationship, such as a child object pointing to its parent.
  • Use weak self in closures stored by the object that created them, especially when asynchronous work may outlive the object.
  • Use strong references deliberately when you want shared ownership and a resource should remain alive while in use.

6. Common Mistakes

Mistake 1: Creating a retain cycle with two strong references

Two classes can keep each other alive forever if both sides hold strong references. This is one of the most common ARC problems in Swift.

Problem: Neither object can be released because each one increases the other's reference count.

Swift
class Person {
    var apartment: Apartment?
}

class Apartment {
    var tenant: Person?
}

Fix: Make the back-reference weak when the apartment should not own the tenant.

Swift
class Person {
    var apartment: Apartment?
}

class Apartment {
    weak var tenant: Person?
}

The corrected version works because the apartment no longer keeps the person alive forever.

Mistake 2: Declaring a weak property as non-optional

A weak reference can become nil automatically, so Swift requires it to be optional.

Problem: Swift reports that weak properties must be declared optional because the referenced object may disappear at any time.

Swift
class Owner {}

class Widget {
    weak var owner: Owner
}
Compiler output✓ Tested · Swift 6.4
error: 'weak' variable should have optional type 'Owner?'

Fix: Add the optional marker to the weak reference.

Swift
class Owner {}

class Widget {
    weak var owner: Owner?
}

The corrected version compiles because Swift can set the property to nil when the owner goes away.

Mistake 3: Using unowned when the object can disappear first

Unowned is not a safer weak reference. It is a promise that the reference will always be valid when used.

Problem: If the referenced instance is deallocated first, accessing an unowned reference causes a runtime crash with a message similar to Attempted to read an unowned reference but object was already deallocated.

Swift
class Profile {}

class SettingsScreen {
    unowned var profile: Profile

    init(profile: Profile) {
        self.profile = profile
    }
}

Fix: Use weak when the object may disappear before the reference is used.

Swift
class Profile {}

class SettingsScreen {
    weak var profile: Profile?

    init(profile: Profile) {
        self.profile = profile
    }
}

The corrected version avoids a crash by allowing the reference to become nil safely.

7. Best Practices

Prefer strong references by default

Strong references are the normal ownership model in Swift. Use them unless you have a specific reason not to.

Swift
class Cache {
    var items: [String] = []
}

This is better than trying to make everything weak, because weak references do not express ownership and can vanish unexpectedly.

Use weak for back-references and delegates

If one object points back to another but should not keep it alive, weak is usually the right choice.

Swift
protocol PlayerDelegate: AnyObject {
    func playerDidFinish()
}

class Player {
    weak var delegate: PlayerDelegate?
}

This keeps ownership simple and makes object lifetimes easier to reason about.

Use unowned only when the lifetime relationship is guaranteed

Unowned can be appropriate, but only when the referenced object must outlive the reference.

Swift
class Country {
    let name: String
    init(name: String) { self.name = name }
}

class City {
    unowned let country: Country

    init(country: Country) {
        self.country = country
    }
}

If that guarantee is not absolute, choose weak instead.

8. Limitations and Edge Cases

  • Weak references can only be used with class types and protocols constrained to AnyObject.
  • A weak reference becomes nil automatically, so every use must handle optionality.
  • Unowned references do not become nil; accessing them after deallocation crashes at runtime.
  • Collections like arrays and dictionaries hold strong references to their elements by default.
  • Closures capture class instances strongly unless you use a capture list such as [weak self] or [unowned self].
  • Using unowned with asynchronous callbacks is risky if the callback might fire after the owner is gone.

9. Practical Mini Project

Here is a small, complete example that models a study group. The group owns its members strongly, but each member only keeps a weak reference to the group so there is no retain cycle.

Swift
final class StudyGroup {
    let name: String
    private var members: [Student] = []

    init(name: String) {
        self.name = name
    }

    func add(student: Student) {
        members.append(student)
        student.join(group: self)
    }

    func listMembers() {
        print("Group: \(name)")
        for member in members {
            print("- \(member.name)")
        }
    }
}

final class Student {
    let name: String
    weak var group: StudyGroup?

    init(name: String) {
        self.name = name
    }

    func join(group: StudyGroup) {
        self.group = group
    }

    func showMembership() {
        if let group {
            print("\(name) belongs to \(group.name)")
        } else {
            print("\(name) is not in a group")
        }
    }
}

do {
    let group = StudyGroup(name: "Swift Basics")
    let student = Student(name: "Mina")

    group.add(student: student)
    group.listMembers()
    student.showMembership()
}
Output✓ Tested · Swift 6.4
Group: Swift Basics
- Mina
Mina belongs to Swift Basics

This mini project shows a practical ownership model: the group owns its members, while members can refer back without preventing the group from being released.

10. Key Points

  • Strong references are Swift's default and keep objects alive.
  • Weak references do not own objects and automatically become nil.
  • Unowned references do not own objects either, but they must never be used after deallocation.
  • Weak is the safest choice when the referenced object may disappear.
  • Unowned is best only when the lifetime relationship is guaranteed.
  • Retain cycles usually happen when two objects strongly reference each other or when closures capture self too strongly.

11. Practice Exercise

Create a simple model of a Teacher and a Classroom:

  • The classroom should strongly own its teacher.
  • The teacher should hold a weak reference back to the classroom.
  • Add a method that prints whether the teacher is currently assigned to a classroom.

Expected output: The program should print the classroom name while the classroom exists, and then report that the teacher has no classroom after the classroom is released.

Hint: Make the back-reference optional and use if let before reading it.

Show solution
Swift
final class Classroom {
    let name: String
    let teacher: Teacher

    init(name: String, teacher: Teacher) {
        self.name = name
        self.teacher = teacher
        teacher.assign(classroom: self)
    }
}

final class Teacher {
    let name: String
    weak var classroom: Classroom?

    init(name: String) {
        self.name = name
    }

    func assign(classroom: Classroom) {
        self.classroom = classroom
    }

    func printStatus() {
        if let classroom {
            print("\(name) teaches in \(classroom.name)")
        } else {
            print("\(name) has no classroom")
        }
    }
}

do {
    var room: Classroom? = Classroom(name: "Room 201", teacher: Teacher(name: "Jordan"))
    room?.teacher.printStatus()
    room = nil
}
Output✓ Tested · Swift 6.4
Jordan teaches in Room 201

This solution works because the teacher does not keep the classroom alive, so the classroom can be released normally.

12. Final Summary

Strong, weak, and unowned references are central to Swift memory management. Strong references own objects by default, weak references provide safe non-owning links that can disappear, and unowned references express a non-owning relationship with a guaranteed lifetime.

Most Swift code uses strong references normally and introduces weak references to break retain cycles, especially for delegates and closures. Unowned references are useful in tightly coupled object relationships, but they should be used carefully because they can crash if the lifetime assumption is wrong.

When in doubt, choose the safer option: strong for ownership, weak for optional back-references, and unowned only when you can prove the referenced object will still exist. If you want to go deeper, the next topic to study is retain cycles in closures and how capture lists control ownership.