Classes in Swift
Classes are reference types — when you assign a class instance to a new variable, both variables point to the same object in memory. Changes to one are visible through the other. Use classes when you need identity, shared state, or inheritance.
class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
let buddy = Dog(name: "Buddy", breed: "Golden Retriever")
print(buddy.name) // Buddy
Try it Yourself ->
Inheritance
Classes can inherit properties and methods from other classes. The subclass gets everything the superclass has and can add its own properties and methods or override existing ones. This is one of the key differences between classes and structs.
class Animal {
var name: String
init(name: String) {
self.name = name
}
func speak() -> String {
return "\(name) makes a sound"
}
}
class Cat: Animal {
var isIndoor: Bool
init(name: String, isIndoor: Bool) {
self.isIndoor = isIndoor
super.init(name: name)
}
override func speak() -> String {
return "\(name) meows"
}
}
let kitty = Cat(name: "Whiskers", isIndoor: true)
print(kitty.speak()) // Whiskers meows
Try it Yourself ->
The Override Keyword
When a subclass provides its own implementation of a method or property from its superclass, you must use the override keyword. This tells Swift you intend to replace the inherited behavior and helps catch mistakes at compile time.
class Vehicle {
var speed: Double = 0
func describe() -> String {
return "Speed: \(speed) mph"
}
}
class Car: Vehicle {
var gear = 1
override func describe() -> String {
return "Speed: \(speed) mph, Gear: \(gear)"
}
}
let myCar = Car()
myCar.speed = 60
myCar.gear = 3
print(myCar.describe()) // Speed: 60.0 mph, Gear: 3
Try it Yourself ->
Initializers
Classes have designated initializers that fully initialize all properties, and convenience initializers that call a designated initializer with different parameters. You must call super.init() to ensure the superclass is properly initialized.
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "Unnamed")
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
let egg = RecipeIngredient(name: "Egg")
print("\(egg.name) x\(egg.quantity)") // Egg x1
Try it Yourself ->
Deinitialization
Classes can have a deinit method that runs when an instance is about to be deallocated from memory. This is the place to clean up resources, close connections, or perform any final cleanup.
class BankAccount {
var balance: Double
init(balance: Double) {
self.balance = balance
print("Account opened with \(balance)")
}
deinit {
print("Account closed. Final balance: \(balance)")
}
}
var account: BankAccount? = BankAccount(balance: 1000)
account = nil // Account closed. Final balance: 1000.0
Try it Yourself ->
When to Use Classes
Use classes when you need identity (comparing two instances to see if they're the same object), shared state (multiple parts of your app need to modify the same data), or when you need to interact with Objective-C code. Otherwise, prefer structs.
class Person {
var name: String
init(name: String) {
self.name = name
}
}
let alice = Person(name: "Alice")
let alsoAlice = alice // Same instance, not a copy
alsoAlice.name = "Bob"
print(alice.name) // Bob — both variables point to the same object
// Identity comparison
let anotherPerson = Person(name: "Alice")
print(alice === anotherPerson) // false — different instances
Try it Yourself ->