Memory Management with ARC
Prerequisites: Classes and reference types, Structs vs classes
Swift manages the memory of class instances with Automatic
Reference Counting (ARC). Every class instance keeps a count of how
many strong references point to it. When that count drops to zero,
the instance is freed immediately and its deinit runs.
Real-world analogy: a meeting room booking. Each person who needs the room adds their name to the list; when the last name is crossed off, the room is released at once — no cleaner doing periodic sweeps.
Watching ARC work
final class Session {
let user: String
init(user: String) {
self.user = user
print("\(user): session started")
}
deinit { print("\(user): session ended") }
}
var first: Session? = Session(user: "Ada") // count: 1
var second = first // count: 2
print("Both set: \(first != nil && second != nil)")
first = nil // count: 1
print("Still reachable: \(second?.user ?? "gone")")
second = nil // count: 0 → freed
print("Done")
Ada: session started
Both set: true
Still reachable: Ada
Ada: session ended
Done
The session isn't freed when first is cleared — second still refers
to it. It's freed the moment the last strong reference goes away.
ARC vs garbage collection
Languages like Java, C#, and Go use a garbage collector that periodically finds and frees unused objects. ARC works differently:
- Memory is freed deterministically, at a predictable point — as soon as the last reference disappears. There are no collection pauses.
- The compiler inserts the counting code for you at compile time.
- The trade-off: ARC can't free two objects that refer to each other, even when nothing else uses them. That's a reference cycle — the next lesson.
Value types and ARC
ARC only applies to reference types (classes, actors, and
closures). Structs and enums are copied rather than shared, so there's
nothing to count — one more reason Swift favors value types. (Types
like Array and String use reference-counted storage internally, but
that's hidden behind their value semantics.)
Common mistakes
- Assuming Swift has no memory leaks because it manages memory automatically. Reference cycles leak — see the next lesson.
- Relying on
deinitrunning at an exact line in optimized builds. The compiler may end a reference's lifetime right after its last use, slightly earlier than the end of the scope.