ARC / Strong References / Retain Cycles
| Since: | Swift 1.0(2014) |
|---|
Swift manages memory automatically using ARC (Automatic Reference Counting). An instance of a class is kept in memory as long as there is at least one strong reference to it.
Syntax
// Strong reference (default)
var a: MyClass? = MyClass() // Reference count: 1
var b = a // Reference count: 2
a = nil // Reference count: 1 (b still holds it)
b = nil // Reference count: 0 → released
// Pattern that causes a retain cycle
class A {
var b: B? // A holds a strong reference to B
}
class B {
var a: A? // B holds a strong reference to A → retain cycle!
}
Terminology
| Term | Description |
|---|---|
| ARC (Automatic Reference Counting) | Automatically tracks the number of references to a class instance and frees its memory when the count reaches zero. |
| Strong reference | The default type of reference. Increments the reference count. |
| Reference count | The number of references pointing to an instance. When it reaches zero, the instance is deallocated. |
| Retain cycle | A situation where two instances hold strong references to each other, preventing the reference count from ever reaching zero and causing a memory leak. |
Sample Code
sample_arc_strong_reference.swift
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) created")
}
// 'deinit' is a method called just before the instance is freed from memory.
deinit {
print("\(name) released")
}
}
// Basic strong reference behavior
var ref1: Person? = Person(name: "user_x") // Reference count: 1
var another = ref1 // Reference count: 2
ref1 = nil // Reference count: 1 (another still holds it)
print("Set ref1 to nil")
another = nil // Reference count: 0 → released
print("Set another to nil")
// Retain cycle example (memory leak)
class Apartment {
let unit: String
var tenant: Resident? // Strong reference
init(unit: String) {
self.unit = unit
print("Room \(unit) created")
}
deinit { print("Room \(unit) released") }
}
class Resident {
let name: String
var apartment: Apartment? // Strong reference → retain cycle!
init(name: String) {
self.name = name
print("\(name) created")
}
deinit { print("\(name) released") }
}
// Creating a retain cycle
var apt: Apartment? = Apartment(unit: "101A")
var res1: Resident? = Resident(name: "user_y")
apt!.tenant = res1 // Apartment → Resident (strong reference)
res1!.apartment = apt // Resident → Apartment (strong reference)
apt = nil // Not released (res1 still holds a reference)
res1 = nil // Not released (apt still holds a reference)
print("--- Neither was released due to the retain cycle ---")
Running the above produces the following output:
swift arc_strong_reference.swift user_x created Set ref1 to nil user_x released Set another to nil Room 101A created user_y created --- Neither was released due to the retain cycle ---
Notes
ARC does not apply to structs, enums, or primitive types. Only instances of classes (reference types) are managed by ARC.
When a retain cycle occurs, the reference count never reaches zero and deinit is never called. Retain cycles cause memory leaks. Use weak or unowned to break the cycle.
For details on resolving retain cycles with weak and unowned, see weak / unowned.
If you find any errors or copyright issues, please contact us.