A struct's instances are value types: assigning one to a new variable, or passing it to a function, creates a genuinely independent copy — mutating the copy never affects the original. A class's instances are reference types: assignment shares the SAME underlying object between variables, so mutating it through one reference is visible through every other reference to that same instance. Structs also get a free memberwise initializer generated automatically from their properties, with no manual init needed for the simple case. Apple's official guidance is explicit: default to structs, and use a class specifically when identity (is this the SAME object, not just an equal one) or shared mutable state is genuinely part of the design.
Structs: copied on assignment, with a free initializer
p2 is a genuinely INDEPENDENT copy — modifying it afterward has zero effect on p1, since they stopped being connected the instant the assignment happened.
struct Point {
var x: Int
var y: Int
} // memberwise init(x:y:) generated automatically — no manual init needed
var p1 = Point(x: 1, y: 2)
var p2 = p1 // COPIES p1 — p2 is now independent
p2.x = 100
print(p1.x) // 1 — p1 is completely unaffected by the change to p2Classes: shared by reference
c1 and c2 refer to the EXACT SAME underlying object — modifying through c2 is visible through c1 too, since there was never a second, independent copy created.
class Counter {
var count = 0
}
let c1 = Counter()
let c2 = c1 // SHARES the same instance — not a copy
c2.count = 100
print(c1.count) // 100 — c1 sees the change, since c1 and c2 are the SAME objectChoosing between them: Apple's own guidance
Structs are the default for exactly this reason — value semantics are easier to reason about, since a struct's data can never be unexpectedly mutated by unrelated code holding a different reference to "the same" value.
struct User { // struct: no need for shared identity — value semantics are simpler
var name: String
}
class BankAccount { // class: genuinely needs shared, mutable identity across references
var balance: Double = 0
}