Chapter 83: Swift Class Methods
1. What is a method in a class?
A method is simply a function that belongs to a class (or struct/enum).
There are two kinds:
- Instance methods → Belong to each individual object (instance) → Called on an instance: myObject.doSomething()
- Type methods (static / class methods) → Belong to the type itself (the class), not to any particular instance → Called on the type name: MyClass.doSomething()
Think of it like this:
- Instance method = “Each person can tell you their own name” → rahul.introduce() → “I’m Rahul” → priya.introduce() → “I’m Priya”
- Type method = “The Person class can tell you something about all people” → Person.averageAge() → “Average age of all people is 28”
2. Instance Methods – the most common type
These are the normal methods you write inside a class.
|
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 |
class Person { let name: String var age: Int init(name: String, age: Int) { self.name = name self.age = age } // Instance method — called on a specific person func introduce() { print("Hi, I'm \(name), \(age) years old.") } func haveBirthday() { age += 1 print("Happy birthday! Now I'm \(age) 🎂") } func canVote() -> Bool { age >= 18 } } // Usage let rahul = Person(name: "Rahul Verma", age: 27) rahul.introduce() // Hi, I'm Rahul Verma, 27 years old. rahul.haveBirthday() // Happy birthday! Now I'm 28 🎂 print(rahul.canVote()) // true |
Key points about instance methods:
- They have implicit access to self (the current instance)
- They can read and modify instance properties (if var)
- They are called on an instance: rahul.introduce()
3. Type Methods — static & class methods
These belong to the type itself, not to any specific object.
There are two kinds:
- static — cannot be overridden in subclasses
- class — can be overridden in subclasses
|
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 |
class Vehicle { static var numberOfWheels: Int { 4 // default for cars } // Can be overridden in subclasses class var isElectric: Bool { false } static func description() -> String { "A vehicle with \(numberOfWheels) wheels" } } class Car: Vehicle { // Cannot override static // static var numberOfWheels: Int { 6 } // compile error // Can override class property override class var isElectric: Bool { true } } class Bicycle: Vehicle { override class var isElectric: Bool { false } // Can override class method override class func description() -> String { "A bicycle with 2 wheels" } } // Usage — called on the type print(Vehicle.numberOfWheels) // 4 print(Vehicle.description()) // A vehicle with 4 wheels print(Car.isElectric) // true (overridden) print(Bicycle.description()) // A bicycle with 2 wheels |
4. Real-life examples — class methods you will actually write
Example 1 – Factory methods (very common pattern)
|
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 |
class User { let id: UUID let name: String let email: String private init(id: UUID, name: String, email: String) { self.id = id self.name = name self.email = email } // Factory method — most common way to create objects static func create(name: String, email: String) -> User? { guard !name.isEmpty, email.contains("@") else { print("Invalid name or email") return nil } return User(id: UUID(), name: name, email: email) } // Convenience factory static func guest() -> User { User(id: UUID(), name: "Guest", email: "guest@example.com") } } // Usage if let user = User.create(name: "Rahul", email: "rahul@example.com") { print("Created user: \(user.name)") } let guest = User.guest() print("Guest user: \(guest.name)") |
Example 2 – Shared / singleton-like (careful — use sparingly)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Logger { static let shared = Logger() private init() {} // private init prevents creating more instances func log(_ message: String) { print("[LOG] \(Date().formatted(date: .abbreviated, time: .standard)) - \(message)") } } // Usage anywhere in the app Logger.shared.log("User logged in") Logger.shared.log("Payment processed") |
Modern note: Singletons are used less in modern Swift. Prefer dependency injection instead.
5. Very Common Beginner Mistakes & Correct Habits
| Mistake | Wrong / Risky code | Correct / Better habit | Why? |
|---|---|---|---|
| Using var for properties that never change | var id: UUID | let id: UUID | let prevents accidental changes |
| Force-unwrapping in methods | self.user!.name | guard let user = user else { return } | Safer, better error handling |
| Making everything public | public class, public var everywhere | Default = internal — use public only when needed | Better encapsulation & API control |
| Forgetting mutating in struct methods | func increase() { age += 1 } | mutating func increase() { age += 1 } | Compile error if missing (structs only) |
| Overusing class inheritance | Deep class hierarchies | Prefer composition + protocols | Easier to test, understand, maintain |
6. Quick Summary — Class Properties Patterns You Will Use Most
| Goal | Typical code | When to prefer it |
|---|---|---|
| Fixed data (identity) | let id: UUID, let createdAt: Date | Always use let when value never changes |
| Changeable data | var balance: Double, var status: String | When value needs to be updated |
| Calculated value | var fullName: String { first + ” ” + last } | When value depends on other properties |
| Expensive object created only when needed | lazy var formatter = DateFormatter() | Heavy initialization (formatters, images, etc.) |
| React to value change | var score: Int { didSet { updateUI() } } | UI updates, saving, logging, validation |
| Read-only public view of private data | private var _balance: Double + var balance: Double { _balance } | Encapsulation + controlled access |
7. Small Practice – Try these
- Create a Person class with:
- let id: UUID
- var name: String
- var age: Int
- computed property isAdult: Bool
- method haveBirthday()
- Create a BankAccount class with:
- private var balance: Double
- init(initialDeposit:)
- var currentBalance: Double (computed)
- methods deposit(amount:) and withdraw(amount:) -> Bool
- Create a TemperatureMonitor class with:
- var celsius: Double { didSet { checkWarning() } }
- private method checkWarning() that prints warning if > 40 or < 10
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 😊
