Classes and Reference Types
Prerequisites: Initializers
A class looks a lot like a struct, with one fundamental difference: classes are reference types. A variable holding a class instance holds a reference to a single shared object, not its own copy.
Syntax
class BankAccount {
let owner: String
private(set) var balance: Double
init(owner: String, balance: Double = 0) {
self.owner = owner
self.balance = balance
}
func deposit(_ amount: Double) {
balance += amount
}
}
Differences from structs you can see here:
- Classes have no automatic memberwise initializer — you write
inityourself. - Methods that change properties don't need
mutating.
Shared references
class BankAccount {
var balance: Double = 0
}
let mine = BankAccount()
let alias = mine // not a copy — the same account
alias.balance = 100
print(mine.balance)
print(mine === alias)
100.0
true
Changing alias changed mine, because both refer to one object.
=== checks whether two references point to the same instance.
Also notice that mine is a let, yet its balance changed. For a
class, let means the variable always refers to the same object — not
that the object's contents are frozen.
deinit
A class can run cleanup code when its instance is destroyed:
class Connection {
init() { print("Connected") }
deinit { print("Disconnected") }
}
do {
let connection = Connection()
print("Using \(type(of: connection))")
}
print("Done")
Connected
Using Connection
Disconnected
Done
When nothing refers to an instance any more — here, when connection
goes out of scope at the end of the do block — Swift frees it
immediately, running deinit. Level 3 explains how this automatic
reference counting works.
Common mistakes
- Passing a class instance into a function and being surprised that the function's changes are visible outside.
- Using a class for simple data where a struct would do — see the next lesson.