When would you still use a class in a Swift-first codebase?
Predict first
Does this compile?
struct FileBox {
let fd: Int32
deinit { close(fd) }
}
- Yes
- No
Predict first
What does this print?
final class Counter { var n = 0 }
struct Tally { let counter = Counter() }
let a = Tally()
let b = a
b.counter.n += 1
print(a.counter.n)
- 0
- 1
- Compile error
Mental model. You do not choose a class because “I might subclass later”. You choose it because something must be one shared thing.
Use a class when you need shared mutable identity that value copies would break: a socket, a video player, a URLSession, a cache. Also when you need deinit for a non-memory resource, must subclass a UIKit/AppKit type, must expose the type to Objective-C, or a framework hands you one.
Actor is increasingly the right answer when that shared identity also needs isolation. A class is the right answer when it must cross an API that predates concurrency, or when the type is genuinely a UI object with a main-thread contract.
A copyable struct has no single owner, so there is no moment to run deinit. Deterministic cleanup is a reason to reach for a class (or a ~Copyable struct).
Copying the struct copies the reference. Both tallies share one Counter. “Always use structs” does not remove sharing; it hides it.
Common traps
- “Classes are for big objects, structs for small ones.” Size is irrelevant. Identity and sharing are what matter.
- “Always use structs” as a rule. It produces giant value types wrapping references, and re-creates the sharing bug the rule was meant to prevent.
They might follow up with
- What about
deinitin a struct? Not available. If cleanup must be deterministic, either use a class ordeferat the call site. - Can an actor be a UI type? Only if it is
@MainActor-isolated; otherwise every call hops off the main thread.
Related questions
- 1.1.1 What is the difference between a value type and a reference type in Swift? When do you choose each?
- 1.1.2 What is the difference between struct, class, and actor?
- 1.1.5 How do you design a public Swift type: struct vs class vs actor vs enum?
← Where do value types live — stack or heap? How do you design a public Swift type: struct vs class vs actor vs… →