What is the difference between a value type and a reference type in Swift? When do you choose each?
Predict first
What does this print?
struct Point { var x = 1 }
var a = Point()
var b = a
b.x = 99
print(a.x)
- 1
- 99
- Compile error
Mental model. A value type is a photocopy of a document. A reference type is a shared Google Doc link — everyone editing it sees the same text.
Value types (struct, enum, tuple) are copied on assignment and on passing into a function. Swift's compiler elides many copies, and stdlib types like Array add copy-on-write so the copy is cheap until mutation.
Reference types (class, actor, closures) copy only the reference. Both variables point at one instance, so mutation through either is visible through both.
Choose a struct when the thing is data, when copies should be independent, or when you are modelling SwiftUI state. Choose a class for shared mutable identity (a socket, a player, a view), inheritance, Objective-C interop, or deinit. Choose an actor when that shared identity must also be data-race isolated.
var b = a copied the struct. b is its own Point, so a.x is still 1. Flip it to a class in the lab below and the answer becomes 99.
Common traps
- “Structs live on the stack.” Only small, non-escaping ones reliably do. Capture a struct in an escaping closure or store it in an existential and it is heap-allocated.
- “A struct is deeply immutable if it is a
let.” If it holds a class reference, the reference is copied but the object is still shared and mutable.
They might follow up with
- What happens when a struct holds a class property? You get a shallow copy — the reference is duplicated, both copies mutate the same object. That is the classic “my struct is not really a value” bug.
- How does SwiftUI exploit value semantics? It compares old and new
Viewvalues to decide whether to re-render; shared mutable references would defeat that.