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 or Core Idea
Strong references
By default, Swift class references are strong. You usually do not write anything special to make a reference strong.
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.
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.
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.
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 = nilWhen 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.
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.
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.
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.
class Person {
var apartment: Apartment?
}
class Apartment {
var tenant: Person?
}Fix: Make the back-reference weak when the apartment should not own the tenant.
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.
class Owner {}
class Widget {
weak var owner: Owner
}Fix: Add the optional marker to the weak reference.
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.
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.
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.
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.
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.
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.
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()
}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.
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
}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.