Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Core Programming Concepts  ›  Lesson

Memory Management with ARC

Memory Management 12 minARC frees a class instance when its strong reference count reaches zero, so strong reference cycles must be broken with weak or unowned references.

Memory Management with ARC

TrailLog's hike detail screen closes, but its memory never comes back. Open and close it twenty times and the app is using far more memory than it should. Nothing crashed; objects simply never got freed. Understanding how iOS frees memory explains why.

The rule

ARC frees an object when its last strong reference disappears.

Swift uses Automatic Reference Counting (ARC) for class instances. Every strong reference to an object adds one to its count; when a reference goes away, the count drops. At zero, the object is destroyed and deinit runs. No garbage collector pauses the app; the counting happens as your code runs.

ARC applies to classes (and closures). Structs and enums are values and are simply copied, so they are not counted.

The problem is a retain cycle: two objects holding strong references to each other. Neither count ever reaches zero, so both leak.

class HikeDetailViewController: UIViewController {
    var onSave: (() -> Void)?
    var hike: Hike?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Leak: the controller owns the closure, and the closure owns the controller.
        onSave = { self.showSavedBanner() }
    }
}

The fix is to make one side weak or unowned:

onSave = { [weak self] in
    self?.showSavedBanner()
}
  • weak — does not add to the count. It must be an optional var, and becomes nil automatically when the object is destroyed. Safe default.
  • unowned — also does not add to the count, but is not optional. Use it only when the other object is guaranteed to outlive this reference; otherwise accessing it crashes.

The classic places cycles hide: closures stored as properties that mention self, and delegates, which is why delegate properties are almost always declared weak var delegate.

The shortcut

Draw an arrow for each strong reference. If the arrows make a loop, break one arrow with weak. Usually the arrow pointing "back up" to the owner is the one to weaken.

Finding a leak in TrailLogStep 1 of 4
  1. Draw the owner's arrow

    The detail screen stores onSave: screen → closure, strong.

The trap is adding [weak self] everywhere by habit and never checking. A closure that is not stored — such as the one passed to UIView.animate — runs and is released, so it creates no cycle.

Drills

Answer fast — trust the rule.

quick drill

When does ARC destroy a class instance?

quick drill

Which of these is managed by ARC?

quick drill

What happens to a weak reference when the object it points to is destroyed?

quick drill

Why are delegate properties usually declared weak var delegate?

Remember

  • ARC frees an object when its last strong reference disappears; it only counts class instances and closures.
  • Shortcut: draw the strong arrows; a loop is a leak, so weaken the back arrow.
  • weak becomes nil safely; unowned crashes if the object is gone.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainFix a leaking screen

TrailLog's MapViewController stores var onRouteChange: (() -> Void)? and sets it to { self.redraw() } in viewDidLoad. The screen's deinit never runs. Explain why, and how to fix it.