Crash Courses · Masters
Structs, Classes & Enums
Understand Swift's value vs. reference semantics, design structs and classes correctly, and use enums with associated values and raw values.
18 min read+175 XP on completionCert: Swift Crash Course
Tap any word in the text below to start reading from there.
Structs, Classes & Enums
The Core Decision: Struct vs. Class
Use struct (value type) when:
- The data is a simple value: a coordinate, a color, a date range
- Copies should be independent (no shared mutable state)
- The type doesn't need inheritance
- Default in Swift — most types in the standard library are structs (String, Array, Dictionary, Int)
Use class (reference type) when:
- Instances must be shared and mutated by multiple owners
- The type needs inheritance
- The type manages external resources (files, network connections)
- Lifetime must be controlled explicitly (ARC, weak references)
---
Structs
struct Point {
var x: Double
var y: Double
// Computed property
var magnitude: Double {
(x * x + y * y).squareRoot()
}
// Memberwise initializer is auto-generated by Swift
// init(x: Double, y: Double) is provided for free
// Custom initializer
init(angle: Double, radius: Double) {
self.x = radius * cos(angle)
self.y = radius * sin(angle)
}
// Must mark mutating — structs are value types
mutating func translate(dx: Double, dy: Double) {
x += dx
y += dy
}
func distance(to other: Point) -> Double {
let dx = x - other.x
let dy = y - other.y
return (dx*dx + dy*dy).squareRoot()
}
}
var p1 = Point(x: 3.0, y: 4.0)
let p2 = Point(x: 0.0, y: 0.0)
print(p1.magnitude) // 5.0
print(p1.distance(to: p2)) // 5.0
p1.translate(dx: 1.0, dy: 0.0)
print(p1) // Point(x: 4.0, y: 4.0)
// Value semantics demonstration
var p3 = p1
p3.x = 100.0
print(p1.x) // 4.0 — p1 is unchanged---
Classes
class BankAccount {
let owner: String
private(set) var balance: Double // readable externally, writable only internally
// Property observer
var transactionCount: Int = 0 {
didSet {
print("Transaction count updated: \(transactionCount)")
}
}
init(owner: String, initialBalance: Double = 0) {
self.owner = owner
self.balance = initialBalance
}
func deposit(_ amount: Double) {
precondition(amount > 0, "Amount must be positive")
balance += amount
transactionCount += 1
}
@discardableResult
func withdraw(_ amount: Double) -> Bool {
guard amount > 0 && amount <= balance else { return false }
balance -= amount
transactionCount += 1
return true
}
var description: String {
"BankAccount[\(owner): $\(String(format: "%.2f", balance)), \(transactionCount) txns]"
}
}
let acct = BankAccount(owner: "Jordan", initialBalance: 500.0)
acct.deposit(250.0)
acct.withdraw(100.0)
print(acct.description)
// Reference semantics demonstration
let acct2 = acct // same object — just another reference
acct2.deposit(1000)
print(acct.balance) // 1650.0 — acct also reflects the change---
Enums
// Basic enum
enum Direction { case north, south, east, west }
let dir = Direction.north
switch dir {
case .north: print("Going north")
case .south: print("Going south")
case .east: print("Going east")
case .west: print("Going west")
}
// Raw values
enum Planet: Int {
case mercury = 1, venus, earth, mars // auto-increments from 1
}
print(Planet.earth.rawValue) // 3
print(Planet(rawValue: 1)!) // mercury
// String raw values
enum HTTPMethod: String {
case get = "GET", post = "POST", put = "PUT", delete = "DELETE"
}
print(HTTPMethod.get.rawValue) // "GET"
// Associated values — the most powerful feature
enum NetworkResult {
case success(data: Data, statusCode: Int)
case failure(error: Error)
case loading
}
func handleResult(_ result: NetworkResult) {
switch result {
case .success(let data, let code):
print("Success \(code): \(data.count) bytes")
case .failure(let error):
print("Error: \(error.localizedDescription)")
case .loading:
print("Loading...")
}
}
// CaseIterable — iterate all cases
enum Season: CaseIterable {
case spring, summer, fall, winter
}
print("Seasons:", Season.allCases) // [spring, summer, fall, winter]
for season in Season.allCases {
print(season)
}---
Enum Methods and Computed Properties
enum Weekday: Int, CaseIterable {
case monday = 1, tuesday, wednesday, thursday, friday, saturday, sunday
var isWeekend: Bool {
self == .saturday || self == .sunday
}
var name: String {
switch self {
case .monday: return "Monday"
case .tuesday: return "Tuesday"
case .wednesday: return "Wednesday"
case .thursday: return "Thursday"
case .friday: return "Friday"
case .saturday: return "Saturday"
case .sunday: return "Sunday"
}
}
func next() -> Weekday {
let nextRaw = (rawValue % 7) + 1
return Weekday(rawValue: nextRaw)!
}
}
print(Weekday.friday.isWeekend) // false
print(Weekday.saturday.isWeekend) // true
print(Weekday.friday.next().name) // SaturdayReading progress
0% read
In this module
Value Semantics
Reference Semantics
Computed Property
Property Observer
0%