Object-Oriented Programming
By the end of this lesson you'll know exactly when to use a struct vs a class — Swift's most important modelling decision — and you'll build your own types with properties, methods, inheritance, and protocols, the foundation of every Swift app.
Learn Object-Oriented Programming in our free Swift course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Swift course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
1️⃣ Structs vs Classes (value vs reference)
This is the single most important idea in Swift. A struct is a value type : when you assign it to another variable, Swift makes a full, independent copy . A class is a reference type : assigning it just hands out another pointer to the same object. Get this right and most Swift "why did that change?!" bugs disappear. Read the worked example, run it, and watch how the copy and the shared object behave differently.
2️⃣ Stored, Computed & Observed Properties
A stored property keeps a value in memory. A computed property stores nothing — it runs a little code to work out its value every time you read it, which keeps related values in sync for free. A property observer like didSet runs automatically whenever a stored property changes, handing you the previous value as oldValue .
🎯 Your Turn: mutate a struct
A method that changes its own struct's properties needs one special keyword. Fill in the two ___ blanks using the // 👉 hints, then run it and match the expected output.
3️⃣ Class Inheritance & Overriding
Only classes support inheritance. A subclass written as class Dog: Animal gets everything the parent has, and can replace any method by marking it override (the keyword is required, so you never override something by accident). Inside a subclass initialiser you call super.init(...) to let the parent set up its own properties first.
4️⃣ Protocols & Protocol-Oriented Programming
A protocol is Swift's version of an interface : a contract listing the properties and methods a type must provide, with no implementation. Structs, classes, and enums can all conform to it. The superpower is the protocol extension — it supplies a default implementation every conformer gets for free. Writing code against protocols rather than concrete types is protocol-oriented programming , and it's the heart of idiomatic Swift.
🎯 Your Turn: conform to a protocol
Make the Robot struct adopt the Greetable protocol and implement the method it requires. Fill in the two blanks, then run it.
Pro Tips
- 💡 Default to a struct. Only switch to a class when you genuinely need shared state, inheritance, or a deinitialiser.
- 💡 Computed over duplicated. If one value can always be derived from another (Fahrenheit from Celsius), make it computed so the two can never drift out of sync.
- 💡 Protocol extensions beat base classes for sharing behaviour across value types — they avoid fragile, deep class hierarchies.
- 💡 Mark classes final when they aren't designed to be subclassed — it documents intent and lets the compiler optimise.
Common Errors (and the fix)
- "Cannot assign to property: 'self' is immutable": a struct method is changing its own property without permission. Mark the method mutating func ... .
- The value-copy surprise: you changed a struct copy and expected the original to update. Structs copy on assignment — if you truly need shared state, use a class instead.
- "Class 'Dog' has no initializers" / "Property not initialized at super.init call": a stored property has no value. Give every non-optional property a value, and set the subclass's own properties before calling super.init(...) .
- "Type 'Robot' does not conform to protocol 'Greetable'": you listed the protocol but didn't implement everything it requires. Add the missing property or method exactly as the protocol declares it.
- "Overriding declaration requires an 'override' keyword": you redefined an inherited method. Add override in front of func .
📋 Quick Reference — struct vs class
Feature
struct (value type)
class (reference type)
On assignment
Copied (independent)
Shared (same object)
Inheritance
No
Yes (single)
Change own property in a method
Needs mutating
Just works
Free initialiser
Yes (memberwise)
No — write init
Override a method
N/A
override func ...
Use it when…
Default choice; simple data
Shared state / inheritance
Frequently Asked Questions
Mini-Challenge: a Vehicle protocol
No blanks this time — just a brief and an outline. Build it yourself, run it, and check your output against the example in the comments. This is exactly how real Swift models a family of related types.
🎉 Lesson Complete!
- ✅ Structs are value types (copied) and classes are reference types (shared) — the key Swift distinction
- ✅ Properties come in three flavours: stored , computed , and observed with didSet
- ✅ Changing a struct from inside a method needs mutating ; an init sets up a new instance
- ✅ Classes support inheritance ; replace a method with override and call super.init
- ✅ Protocols are Swift's interfaces; protocol extensions add defaults — the basis of protocol-oriented programming
- ✅ Next lesson: SwiftUI Basics — use these types to build real user interfaces
Practice quiz
What happens when you assign a struct to another variable?
- They share one object
- An independent copy is made
- It throws an error
- The original becomes nil
Answer: An independent copy is made. Structs are value types, so assignment makes an independent copy.
A class in Swift is a...
- Value type
- Constant
- Reference type
- Protocol
Answer: Reference type. Classes are reference types; assigning shares the same object.
Which keyword lets a struct method change its own properties?
- override
- static
- private
- mutating
Answer: mutating. A struct method that mutates its own state must be marked mutating.
A computed property...
- Calculates its value on each read with no storage
- Stores a value in memory
- Runs only once
- Cannot be read
Answer: Calculates its value on each read with no storage. A computed property has no storage; it runs code every time it's read.
Which types can conform to a protocol?
- Only classes
- Structs, classes, and enums
- Only structs
- Only enums
Answer: Structs, classes, and enums. Structs, classes, and enums can all conform to protocols.
Which keyword is required to replace an inherited method?
- super
- replace
- override
- final
Answer: override. You must mark a replacing method with override.
Can a struct inherit from another struct?
- Yes
- Only with a protocol
- Only one level
- No, only classes support inheritance
Answer: No, only classes support inheritance. Inheritance is a class-only feature; structs use protocols to share behaviour.
What does a property observer didSet do?
- Runs code after the property changes
- Computes the value
- Prevents changes
- Initialises the type
Answer: Runs code after the property changes. didSet runs automatically each time the stored property changes.
What gives every protocol conformer a default method for free?
- A subclass
- An initialiser
- A protocol extension
- A computed property
Answer: A protocol extension. A protocol extension supplies default implementations to all conformers.
Which call lets a subclass init run the parent's initialiser?
- parent.init()
- base.init()
- self.init()
- super.init()
Answer: super.init(). super.init(...) calls the parent class's initialiser.
Continue this course
- Previous: Functions and Closures
- Next: SwiftUI Basics