0Pricing
Swift Academy · Lesson

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 deinit

Closure 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 strongly

Break 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 cycle

Checklist

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

  1. ARC basics: strong / weak / unowned
  2. Retain cycles & breaking with weak/unowned
  3. Value types to reduce sharing
← Back to Swift Academy