ARC / Strong References / Retain Cycles
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
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) was created")
}
deinit {
print("\(name) was released")
}
}
// Basic strong reference behavior
var alice: Person? = Person(name: "Alice") // Reference count: 1
var another = alice // Reference count: 2
alice = nil // Reference count: 1 (another still holds it)
print("Set alice 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("Apartment \(unit) was created")
}
deinit { print("Apartment \(unit) was released") }
}
class Resident {
let name: String
var apartment: Apartment? // Strong reference → retain cycle!
init(name: String) {
self.name = name
print("\(name) was created")
}
deinit { print("\(name) was released") }
}
// Creating a retain cycle
var apt: Apartment? = Apartment(unit: "101")
var bob: Resident? = Resident(name: "Bob")
apt!.tenant = bob // Apartment → Resident (strong reference)
bob!.apartment = apt // Resident → Apartment (strong reference)
apt = nil // Not released (Bob still holds a reference)
bob = nil // Not released (apt still holds a reference)
print("--- 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.