Skip to content
Theory · Classes · lesson 9 of 10

Struct or class

You now have two pictures. A struct is a form: assignment makes a photocopy, and the copy is filled in separately. A class is a shared document: tags lead to it, and an edit through one tag is seen through all of them. Which one to choose depends on what the program has to do.

Take a game. A player has a score, and several parts of the program work with the player at once: the team, the leaderboard, the profile screen. The score must match everywhere, so the player is one shared instance:

SWIFT
class Player {
    var score = 0
}

let hero = Player()
let team = [hero]
hero.score += 5
print(team[0].score) // 5
print(team[0] === hero) // true

Let's go through the program:

  1. hero is a reference to a Player instance.
  2. team = [hero] puts one more reference to the same instance into an array. The array copies the reference, not the player.
  3. hero.score += 5 changes the shared player, so team[0].score is 5 too.
  4. team[0] === hero answers true: it is one instance.

The position of a piece on the board, though, is only a number. If you save the starting position and then move the piece, the starting one must stay as it was. Here you need a copy, that is, a struct:

SWIFT
struct Position {
    var x = 0
}

let start = Position()
var current = start
current.x += 3
print(start.x, current.x) // 0 3

current is a copy of start, so moving current does not touch start, and the program prints 0 3.

How to choose

A struct by default

Apple recommends starting with a struct. Use one when the value describes data: a position, an amount of money, settings. Everyone who gets a struct works with their own copy, and nobody changes it behind your back.

A class for a shared instance

Use a class if at least one of these is true:

  • several parts of the program change one and the same thing and must see each other's edits: a player, a bank account, an open document;
  • it matters whether it is the same instance or another one with the same properties, that is, you need the === check;
  • you need inheritance.

Here the photocopy picture falls short. A real photocopy costs paper, but a copy of a small struct costs almost nothing. Swift copies an array inside it only right before the first change, as you saw in the arrays theme. So there is no need to choose a class to save on copies.

The interview answer

"How does a struct differ from a class?" is one of the most frequent questions in a Swift interview. You can build the answer like this:

  1. A struct is a value type: assignment and passing to a function copy the value. A class is a reference type: the reference is copied, and all the names lead to one instance.
  2. let on a struct freezes the whole value, and on a class only the reference.
  3. Struct methods that change properties are marked mutating; class methods do not need it.
  4. A struct gets a memberwise initializer by itself, while a class with a property that has no default value needs its own init.
  5. Only classes have inheritance and the === check.

Finish with how to choose: a struct by default, and a class when you need a shared instance, the === check or inheritance.

Common mistake

A class is used for data that must be copied. A position is saved, and then the piece is moved:

SWIFT
class Spot { // ✗
    var x = 0
}

let saved = Spot()
let piece = saved
piece.x += 3
print(saved.x) // 3

The program prints 3, not 0: let piece = saved copied the reference, so moving the piece changed the saved position. A position is data, so Spot should be a struct. Then piece is declared with var, and the program prints 0.

Key points

  • A struct is copied on assignment and passing, while a class instance stays shared by all its references.
  • A struct is the default choice.
  • A class is needed when several parts of the program change one thing, the === check matters or inheritance is required.
  • Inheritance and === exist only for classes, while mutating and the memberwise initializer belong to structs.