Retain cycles & breaking with weak/unowned
Spot retain cycles between objects and closures, then break them using weak and unowned references safely.
Retain cycles & breaking with weak/unowned is a free Swift Academy lesson on CoddyKit — lesson 2 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What is a retain cycle?
A retain cycle happens when objects (or closures) keep strong references to each other so ARC never reaches zero. Break cycles with weak or unowned.
Object ↔ object cycle
Two strong references in both directions create a leak: neither object can drop to zero.
final class Owner {
var gadget: Gadget?
deinit { print("Owner deinit") }
}
final class Gadget {
var owner: Owner?
deinit { print("Gadget deinit") }
}
// Strong ⇄ strong (cycle)
var o: Owner? = Owner()
var g: Gadget? = Gadget()
o!.gadget = g
g!.owner = o
o = nil // no deinit
g = nil // still no deinit (leak)Break with weak
Make one side weak (often the back-reference like delegate/owner) to allow ARC to release both.
final class Owner2 {
var gadget: Gadget2?
deinit { print("Owner2 deinit") }
}
final class Gadget2 {
weak var owner: Owner2? // weak breaks cycle; becomes nil automatically
deinit { print("Gadget2 deinit") }
}
var o2: Owner2? = Owner2()
var g2: Gadget2? = Gadget2()
o2!.gadget = g2
g2!.owner = o2
o2 = nil // Owner2 deinit
g2 = nil // Gadget2 deinitClosure cycle (strong self)
Closures capture variables strongly by default. If the object also owns the closure, that forms a cycle.
final class TimerClient {
var tick: (() -> Void)?
deinit { print("TimerClient deinit") }
func start() {
// BAD: closure strongly captures self; self keeps tick strongly
tick = {
print("tick from", self) // strong capture of self
}
}
}
var c: TimerClient? = TimerClient()
c!.start()
c = nil // no deinit — closure holds self stronglyBreak with capture lists
Use [weak self] (optional) for safe cleanup; use [unowned self] only if self is guaranteed alive when the closure executes.
final class TimerClient2 {
var tick: (() -> Void)?
deinit { print("TimerClient2 deinit") }
func start() {
// Use [weak self] when self can go away before tick runs
tick = { [weak self] in
guard let self = self else { return } // safe unwrap
print("tick from", self)
}
// Alternative when lifetime is guaranteed: [unowned self]
// tick = { [unowned self] in print("tick from", self) }
}
}
var c2: TimerClient2? = TimerClient2()
c2!.start()
c2 = nil // deinit now prints — no cycleChecklist
Checklist:
- Two-way references? Make one side weak (e.g., delegate).
- Closures stored on a type? Capture [weak self] and unwrap safely.
- Use [unowned self] only when lifetime is guaranteed; otherwise it can crash.
Weak vs unowned in closures
Quick check: Which capture list is safer when the object may be released?
Recap
Recap: Identify cycles in objects and closures. Break them with weak or unowned appropriately; prefer weak when in doubt.
Frequently asked questions
Is the “Retain cycles & breaking with weak/unowned” lesson free?
Yes — the full text of “Retain cycles & breaking with weak/unowned” is free to read here on the web, and the Swift Academy course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.
What will I learn in “Retain cycles & breaking with weak/unowned”?
Spot retain cycles between objects and closures, then break them using weak and unowned references safely. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Swift Academy?
No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 3, so you can start here or from the beginning and move at your own pace.
How long does the “Retain cycles & breaking with weak/unowned” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Swift Academy lesson?
Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- ARC basics: strong / weak / unowned
- Retain cycles & breaking with weak/unowned
- Value types to reduce sharing