Chapter 80: Swift Structs
1. What is a Struct? (the clearest possible explanation)
A struct (structure) is a value type that lets you group related data together and usually add behavior (methods) to that data.
In simple words:
A struct is like a custom data bag that you design yourself.
Real-life analogy (the one that clicks for almost everyone):
Think of a visiting card / name card you give someone at a meeting.
That card contains:
- Your name
- Your phone number
- Your company
- Your email
- Your designation
You can make thousands of copies of your card and give them to people — each copy is independent.
If someone writes a note on their copy (“call him tomorrow”), your original card doesn’t change.
That is exactly how structs behave in Swift.
- When you assign a struct to a new variable → you get a full copy (not a reference)
- Changing one copy does not affect any other copy
This is the opposite of classes (which are reference types).
2. Creating your first struct — every part explained
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
struct Person { // Stored properties — the actual data let name: String // cannot be changed after creation var age: Int // can be changed later var city: String? // optional — may be nil // Computed property — calculated on the fly var greeting: String { let cityText = city ?? "somewhere" return "Hi, I'm \(name), \(age) years old, from \(cityText)" } // Method — behavior mutating func haveBirthday() { age += 1 print("Happy birthday! Now I'm \(age) 🎂") } // Initializer (custom — optional) init(name: String, age: Int, city: String? = nil) { self.name = name self.age = age self.city = city } } |
3. Creating objects (instances) from the struct
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// Create concrete persons var rahul = Person(name: "Rahul Verma", age: 27, city: "Bengaluru") var priya = Person(name: "Priya Reddy", age: 24) // Use them print(rahul.greeting) // Hi, I'm Rahul Verma, 27 years old, from Bengaluru print(priya.greeting) // Hi, I'm Priya Reddy, 24 years old, from somewhere // Change mutable property rahul.age = 28 rahul.haveBirthday() // Happy birthday! Now I'm 29 🎂 // Important: priya is unchanged print(priya.age) // still 24 // Assigning creates a COPY var anotherRahul = rahul anotherRahul.age = 50 print(rahul.age) // still 29 — copy was modified, original unchanged print(anotherRahul.age) // 50 |
Key memory fact (you must understand this):
Structs are value types → assigning var b = a → full copy is made → changing b never changes a
(Classes are reference types — both variables point to the same object in memory.)
4. Real-life examples — structs you will actually write every day
Example 1 – Product in shopping cart / e-commerce
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
struct Product { let id: String let name: String let price: Decimal var quantity: Int = 1 var subtotal: Decimal { price * Decimal(quantity) } mutating func increaseQuantity(by step: Int = 1) { quantity += step } mutating func decreaseQuantity(by step: Int = 1) { guard quantity > step else { return } quantity -= step } } var cart: [Product] = [] cart.append(Product(id: "P001", name: "Wireless Earbuds", price: 3499)) cart.append(Product(id: "P002", name: "Phone Case", price: 799)) // Increase quantity of first item cart[0].increaseQuantity(by: 2) var total: Decimal = 0 for item in cart { total += item.subtotal } print("Cart total: ₹\(total)") |
Example 2 – Todo / Task item (very common in productivity apps)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
struct TodoItem { let id: UUID = UUID() var title: String var isCompleted: Bool = false let createdAt: Date = Date() mutating func toggleCompletion() { isCompleted.toggle() } var statusEmoji: String { isCompleted ? "✅" : "⏳" } } var todos: [TodoItem] = [] todos.append(TodoItem(title: "Finish Swift lesson")) todos.append(TodoItem(title: "Buy groceries")) todos[0].toggleCompletion() for todo in todos { print("\(todo.statusEmoji) \(todo.title)") } |
Example 3 – Location / coordinate (very common in maps & location apps)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
struct Location { let latitude: Double let longitude: Double var name: String? var coordinateString: String { String(format: "%.4f, %.4f", latitude, longitude) } func distance(to other: Location) -> Double { // simple Euclidean distance (real app would use proper haversine) let dx = latitude - other.latitude let dy = longitude - other.longitude return sqrt(dx*dx + dy*dy) } } let hyderabad = Location(latitude: 17.3850, longitude: 78.4867, name: "Hyderabad") let bangalore = Location(latitude: 12.9716, longitude: 77.5946, name: "Bengaluru") print("Distance approx: \(hyderabad.distance(to: bangalore))") print("Hyderabad coordinates: \(hyderabad.coordinateString)") |
5. Very Common Beginner Mistakes & Correct Habits
| Mistake | Wrong / Risky code | Correct / Better habit | Why? |
|---|---|---|---|
| Using var for everything | var name: String everywhere | Default to let unless you actually reassign | let prevents bugs + better safety |
| Force-unwrapping optionals in struct | var city: String = address!.city | var city: String? or proper optional handling | Crash if address is nil |
| Making everything public | public struct User { … } everywhere | Default = internal — use public only when needed | Better encapsulation & API control |
| Forgetting mutating for methods that change self | func increaseAge() { age += 1 } | mutating func increaseAge() { age += 1 } | Compile error if missing mutating |
| Using class when struct is better | class Point { let x: Double; let y: Double } | Use struct unless you need reference semantics | Struct is safer, faster, thread-safe by default |
6. Quick Summary — Struct vs Class (decision you make every day)
| Question / Feature | Struct (value type) | Class (reference type) | Most developers choose… |
|---|---|---|---|
| Identity matters (=== checks same instance) | No — every copy is independent | Yes — two variables can point to same object | Struct unless identity matters |
| Can inherit from another type | No | Yes (single inheritance) | Struct unless you need inheritance |
| Can be used as key in Dictionary/Set | Yes (if Hashable) | Yes (but need careful Hashable implementation) | Struct almost always |
| Copy behavior | Copied on assignment / pass | Reference (pointer) copied | Struct safer |
| Thread safety (mutable shared state) | Safer (each copy independent) | Can cause data races | Struct preferred |
| Typical use in SwiftUI | @State, @ObservedObject (structs) | ObservableObject / @StateObject | Struct for most data |
Modern Swift recommendation (2025–2026):
Default to struct for almost everything Use class only when you need:
- reference semantics (shared mutable state)
- inheritance
- Objective-C interop
- identity comparison (===)
7. Small Practice — Try these
- Create a Person struct with:
- let name: String
- var age: Int
- mutating func haveBirthday()
- Create a BankAccount struct like the example above
- private var balance: Double
- init(initialDeposit:)
- mutating func deposit(amount:)
- mutating func withdraw(amount:) -> Bool
- Create a Location struct like the example
- let latitude: Double, longitude: Double
- var name: String?
- computed coordinateString
Paste your code here if you want feedback or want to see more polished versions!
What would you like to explore next?
- Struct vs Class — detailed comparison & decision guide
- Mutability inside structs (mutating methods)
- Struct initializers (default, custom, memberwise)
- Structs in SwiftUI (@State, value types, performance)
- Or move to another topic (optionals, arrays, closures, switch…)
Just tell me — we’ll continue in the same clear, detailed, patient style 😊
