Chapter 79: Swift Classes/Objects
1. What is a class? What is an object? (the clearest possible explanation)
Class = the blueprint / recipe / template Object = one actual thing made from that blueprint
Real-life analogy (the one that clicks for almost everyone):
- Class = the design / blueprint of a smartphone (screen size, camera specs, battery type, how buttons work…)
- Object = one actual phone made from that blueprint → My iPhone 14 Pro → Your iPhone 15 → Your friend’s iPhone 13
Both phones follow the same design (same class), but each phone has its own:
- own phone number
- own photos
- own battery level
- own wallpaper
That is the core idea:
Class defines what every object of that type knows and can do. Object is one concrete instance with its own specific values.
2. Creating a class – basic syntax
|
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 |
class Person { // Properties (data) let name: String // cannot be changed after creation var age: Int // can be changed later var city: String? // optional – may be nil // Initializer (how to create an object) init(name: String, age: Int, city: String? = nil) { self.name = name self.age = age self.city = city } // Method (behavior) func introduce() { let cityText = city ?? "somewhere" print("Hi, I'm \(name), \(age) years old, from \(cityText)") } func haveBirthday() { age += 1 print("Happy birthday! Now \(name) is \(age) years old 🎂") } } |
3. Creating objects (instances) from the class
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// Create concrete objects let rahul = Person(name: "Rahul Verma", age: 27, city: "Bengaluru") let priya = Person(name: "Priya Reddy", age: 24) // Use them rahul.introduce() // Hi, I'm Rahul Verma, 27 years old, from Bengaluru priya.introduce() // Hi, I'm Priya Reddy, 24 years old, from somewhere rahul.haveBirthday() // Happy birthday! Now Rahul Verma is 28 years old 🎂 // rahul and priya are different objects print(rahul.age) // 28 print(priya.age) // 24 (unchanged) |
Important memory fact:
- rahul and priya are two separate objects
- Changing one does not affect the other
- Classes are reference types — variables hold references (pointers) to the object in memory
4. Real-life examples — classes you will actually write
Example 1 – BankAccount (classic encapsulation example)
|
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 40 41 42 43 44 45 46 47 48 49 |
class BankAccount { let accountNumber: String private var balance: Double = 0.0 init(accountNumber: String, initialDeposit: Double) { self.accountNumber = accountNumber deposit(amount: initialDeposit) } var currentBalance: Double { balance } func deposit(amount: Double) { guard amount > 0 else { print("Deposit amount must be positive") return } balance += amount print("Deposited ₹\(amount). New balance: ₹\(balance)") } func withdraw(amount: Double) -> Bool { guard amount > 0 else { print("Withdrawal amount must be positive") return false } guard amount <= balance else { print("Insufficient funds") return false } balance -= amount print("Withdrew ₹\(amount). New balance: ₹\(balance)") return true } } // Real usage let savingsAccount = BankAccount(accountNumber: "SB-123456", initialDeposit: 25000) savingsAccount.deposit(amount: 10000) _ = savingsAccount.withdraw(amount: 5000) print("Current balance: ₹\(savingsAccount.currentBalance)") // savingsAccount.balance = -100000 // ← compile error – private! |
Example 2 – Simple Car class (inheritance + polymorphism)
|
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 40 41 42 43 44 45 46 47 48 49 50 51 |
class Car { let brand: String var currentSpeed: Double = 0.0 init(brand: String) { self.brand = brand } func accelerate(to speed: Double) { currentSpeed = speed print("\(brand) is now going at \(speed) km/h") } func honk() { print("\(brand) says: Beep beep!") } } class ElectricCar: Car { let batteryCapacity: Double init(brand: String, batteryCapacity: Double) { self.batteryCapacity = batteryCapacity super.init(brand: brand) } override func accelerate(to speed: Double) { super.accelerate(to: speed) print("Quiet electric acceleration – zero emissions!") } override func honk() { print("\(brand) says: Beep boop! (electric sound)") } } // Polymorphism in action let vehicles: [Car] = [ Car(brand: "Maruti Swift"), ElectricCar(brand: "Tata Nexon EV", batteryCapacity: 40.5) ] for vehicle in vehicles { vehicle.accelerate(to: 80) vehicle.honk() } |
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 accidental changes + better safety |
| Force-unwrapping in class methods | self.user!.name | guard let user = user else { return } | Safer, better error handling |
| Deep inheritance hierarchies | 5+ levels of inheritance | Prefer composition or protocols | Deep trees become hard to maintain |
| Making everything public | public class, public var everywhere | Use internal (default) or private when possible | Better encapsulation & API control |
| Mutating shared state without care | static var sharedBalance | Prefer dependency injection over singletons | Singletons make testing & reasoning hard |
6. Quick Summary – Classes vs Structs (the decision you make every day)
| Feature / Question | Class (reference type) | Struct (value type) | When most developers choose |
|---|---|---|---|
| Identity matters (same object, same instance) | Yes — two variables can point to same object | No — copying creates independent value | Class when identity matters (shared state) |
| Inheritance supported | Yes | No | Class when you need inheritance |
| Can be used as key in Dictionary/Set | No (unless you implement Hashable carefully) | Yes (if Hashable) | Struct almost always for value types |
| Memory management | Reference counting (ARC) | Copied on write (Copy-on-Write for Array, Dict…) | Struct safer for value semantics |
| Thread safety (mutable shared state) | Can cause problems | Safer (each copy independent) | Struct preferred in modern Swift |
| Typical use in SwiftUI | ObservableObject / @StateObject | @State, @ObservedObject (structs) | Structs for most data models |
Modern Swift recommendation (2025–2026):
Use struct by default 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 class with:
- let name: String
- var age: Int
- method haveBirthday() that increases age
- Create a BankAccount class like the example above
- private balance
- deposit & withdraw methods
- read-only currentBalance
- Create ElectricCar that inherits from Car
- override honk() to say something electric
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
- Inheritance vs composition (modern preference)
- Protocol-oriented programming (POP)
- Access control (private, fileprivate, internal, public, open)
- OOP in SwiftUI (ObservableObject, @StateObject…)
- Or move to another topic (optionals, arrays, closures, switch…)
Just tell me — we’ll continue in the same clear, detailed, patient style 😊
