Published on

Automatic Reference Counting in Swift

Authors
  • avatar
    Name
    Rosa Tiara
    Twitter

Introduction

Imagine your app is a theater. Objects (instances of classes) are the seats, and references are the people occupying them. Automatic Reference Counting (ARC) is Swift's memory management system that keeps track of how many references there are to each object, ensuring memory is only used when necessary.

It acts like the theater manager, making sure seats are only reserved when needed and are freed when no one is sitting in them. Let’s learn how ARC works and how to avoid issues like "permanently reserved seats" (retain cycles).

How does ARC work?

ARC automatically manages the lifecycle of objects by counting references.

  • When a person (reference) sits in a seat (object), the reference count goes up.
  • When they leave, the count goes down.
  • If the seat is empty (reference count reaches zero), ARC marks it as available (frees memory).
class Seat {
    let number: Int
    init(number: Int) { self.number = number }
    deinit { print("seat \(number) is now free!") }
}

var seat1: Seat? = Seat(number: 123)
seat1 = nil // ARC frees memory; "seat 123 is now free!" is printed.

Retain Cycles: The Unavailable Seat Problem

Sometimes, two seats in the theater are "reserved" for each other in such a way that neither can be freed up, even when no one is sitting in them. This is called a retain cyclea situation where two objects hold strong references to each other, forming a loop.

As a result, ARC can't free their memory because their reference counts never reach zero! It's like if two people booked the same seat for themselves, and neither wants to give it up, keeping it occupied forever.

Example of a Retain Cycle

Theater.swift
class Ticket {
  var seat: Seat?
}

class Seat {
    var ticket: Ticket?
}

let ticket = Ticket()
let seat = Seat()

ticket.seat = seat
seat.ticket = ticket

How do we solve retain cycles then?

Swift provides two tools to solve this: weak and unowned references.

weak

A weak reference is like a temporary seat reservation that can be canceled. If no one else is using the seat, ARC frees it.

class Ticket {
    weak var seat: Seat?
}

Use weak when one object may outlive the other. weak references automatically become nil when the object they point to is deallocated.

unowned

An unowned reference is like a permanent reservation tied to the life of the ticket. If the ticket is gone, the reference becomes invalid (and crashes if accessed).

class Ticket {
    unowned var seat: Seat
}

Use unowned when both objects are guaranteed to exist and be deallocated together.

Best Practices for ARC in Swift

  1. Use weak or unowned wisely

Understand the relationship between objects to decide whether to use weak or unowned. Use weak if one object might outlive the other, and use unowned when the objects will always have identical lifespans.

  1. Break cycles explicitly

If you no longer need a reference, explicitly set it to nil to allow ARC to do its job.

  1. Debug retain cycles

Use tools like Xcode’s memory graph debugger to detect retain cycles in your app.


In conclusion, Automatic Reference Counting (ARC) is like your app’s memory manager, ensuring that objects are only kept alive when they’re needed. By understanding how ARC works and avoiding retain cycles, you’ll keep your app’s memory usage efficient and prevent leaks that could slow it down.

Got any questions or tips about ARC? Drop them in the comments below and let's continue the conversation!

Hope this helps and happy learning! 🥳