Structs vs. Classes
Value types versus reference types — the distinction that shapes how data moves through a Swift program.
អាន 2 នាទី
Swift gives you two ways to define a custom type with properties and methods: struct and class. They look almost identical to declare, but differ in one fundamental way — value type versus reference type — that affects how data behaves every time it's copied or passed around.
Declaring each
struct Point {
var x: Double
var y: Double
}
class Counter {
var count = 0
}Both can have properties, methods, and initializers. The difference only becomes visible once you copy one.
Structs are value types: copies are independent
struct Point {
var x: Double
var y: Double
}
var pointA = Point(x: 0, y: 0)
var pointB = pointA // pointB is a completely independent copy
pointB.x = 100
print(pointA.x) // 0 — pointA is untouched
print(pointB.x) // 100Assigning pointA to pointB copies the entire value. Changing pointB afterward has zero effect on pointA — they're two separate pieces of data that happen to start out equal.
Classes are reference types: copies share the same instance
class Counter {
var count = 0
}
let counterA = Counter()
let counterB = counterA // counterB points to the SAME instance as counterA
counterB.count = 100
print(counterA.count) // 100 — counterA sees the change toocounterA and counterB aren't two counters — they're two names pointing at the same object in memory. Changing it through either name changes what both see. This is exactly like how object references work in Java or Python.
Why Swift defaults you toward structs
Apple's own guidance, and most idiomatic Swift code, defaults to struct unless you specifically need reference semantics. A few reasons:
- Predictability — a value type can't be changed out from under you by some other part of the code holding the same reference, since there is no shared reference.
- Thread safety — independent copies can't have two threads race to mutate the same instance.
- Most of Swift's own fundamental types —
Int,String,Array,Dictionary— are structs, so working with structs feels like the "default" mode of the language.
When a class is the right call
Reach for class when you genuinely need shared, mutable state — several parts of your code all observing or updating the same underlying object, like a shared view controller in an app, a network session manager, or anything that needs identity (being able to ask "is this the exact same instance as that one?", which === checks for classes but has no equivalent for structs).
Getting this choice right early avoids a whole category of confusing bugs later — where code silently doesn't see a change because it received an independent copy, or unexpectedly does see a change because it shared a reference.