Swift provides two foundational types for creating custom data models: struct and class. While they can look similar in syntax, their behavior is fundamentally different, especially in how they handle memory, identity, and mutability.
Let’s break it down clearly with real examples.
🔵 Class
Class is a reference type.
When you assign one instance to another, both refer to the same memory.
class Person {
var name: String
init(name: String) {
self.name = name
}
}
let p1 = Person(name: "Alice")
let p2 = p1
p2.name = "Bob"
print(p1.name) // Output: Bob
A change in one reflects in the other because both point to the same object.
Classes support inheritance
class Animal {
func sound() -> String {
return "Generic sound"
}
}
class Dog: Animal {
override func sound() -> String {
return "Bark"
}
}
print(Dog().sound()) // Output: Bark
Inheritance allows creating hierarchies and shared behavior.
Classes have an identity you can check if two references are pointing to the same instance using ===.
let a = Person(name: "Eva")
let b = a
print(a === b) // Output: true
They’re not just equal, they’re the same object in memory.
Class instances can have immutable properties and still be modified if declared with let.
class Box {
var weight = 10
}
let box = Box()
box.weight = 20 // ✅ This works
Even though the box is declared with let, you can still modify its properties.
🟢 Struct
Struct is a value type.
struct Car {
var brand: String
}
var car1 = Car(brand: "Tesla")
var car2 = car1
car2.brand = "BMW"
print(car1.brand) // Output: Tesla
Each assignment creates a copy. Changes to one don’t affect the other.
Struct doesn’t support inheritance.
struct Animal {}
// struct Dog: Animal {} ❌ Error
// ✅ Use protocol instead
protocol Walkable {
func walk()
}
struct Dog: Walkable {
func walk() {
print("Dog walking")
}
}
Use protocol-oriented design for code reuse in structs.
Structs don’t have identity; comparison is based on value.
struct Point: Equatable {
var x: Int
var y: Int
}
let p1 = Point(x: 2, y: 3)
let p2 = Point(x: 2, y: 3)
print(p1 == p2) // Output: true
Equality is based on property values, not memory references.
Structs are immutable by default unless you use mutating.
struct Counter {
var count = 0
mutating func increment() {
count += 1
}
}
var counter = Counter()
counter.increment()
print(counter.count) // Output: 1
Without mutating, struct methods can't change properties.
✅ Conclusion
Choose struct if,
- You want value semantics (copies).
- Your data type is small and doesn’t need inheritance.
- You prefer safer, immutable design by default.
Choose a class if,
- You need shared instances and identity.
- You require inheritance.
- You want dynamic dispatch and flexibility.