SwiftQuest

Guide

Structs vs classes in Swift

A struct is copied when you hand it over; a class is shared. Start with a struct, and reach for a class when one thing really has to be seen and changed by everybody.

The one difference that matters

Structs and classes look almost the same: both have properties and methods. The difference is what happens when you assign one, pass it to a function, or put it in an array.

struct Hero {
    var name: String
    var health: Int
}

var hero = Hero(name: "Ash", health: 30)
var shadow = hero        // a second, independent Hero
shadow.health = 8

print(hero.health)       // 30
print(shadow.health)     // 8

The second line made a copy. Changing one cannot reach the other. This is called value semantics, and most of the types in Swift's own library — Int, String, Array, Dictionary — work this way.

Now the same thing with a class:

class Party {
    var gold: Int
    init(gold: Int) { self.gold = gold }
}

let ours = Party(gold: 100)
let theirs = ours        // a second name for the same party
theirs.gold = 40

print(ours.gold)         // 40
print(ours === theirs)   // true: one object, two names

Assigning a class copies the reference, not the object. There is one party, and both names see every change.

What follows from that

  • let means different things. A let struct cannot change at all; a let class reference cannot point elsewhere, but the object it points to can still change — which is why theirs.gold = 40 above was allowed.
  • A struct method that changes the struct says so. It is marked mutating, or Swift refuses it:
    struct Hero {
        var name: String
        var health: Int
    
        mutating func takeHit(_ damage: Int) {
            health -= damage
        }
    }
  • Classes have identity and inheritance; structs have neither. === asks whether two names are the same object, a class can inherit from another, and it can run code in deinit when it goes away.
  • Classes can form reference cycles. Two objects that hold each other strongly are never freed; weak and unowned are how you break the loop. A struct is copied, so it cannot hold on to itself this way.

Which one to choose

Choose a struct by default. A value nobody else can change behind your back is easier to reason about, and Apple's own guidance says the same.

Choose a class when the thing you are modelling is genuinely one thing that several parts of the program must see — a game session everyone at the table watches, a connection, a shared cache — or when a framework asks you to subclass one of its classes.

The test is a question about your design, not about speed: if two parts of the program hold this, should a change made by one be seen by the other? Yes means a class. No means a struct.

Where SwiftQuest teaches it

Structs and copies are The Value Kingdom (island 4): you predict whether one character or two changed, then build and amend values without touching the original. Classes are Reference Citadel (island 6), where a party shares one table, and The Memory Dungeon (island 10) is where reference cycles are found and broken.

Learn it by writing it

SwiftQuest is a Swift course in fifteen islands. Every quest has you write real Swift and run it on a real compiler, in your browser, with nothing to install. It opens soon, and the first two islands are free.