Swift OOP

Swift's classes are reference types while structs are value types, and understanding that distinction is the foundation of everything else in Swift's object model.

#Jobseeker

Find matching jobs & Auto apply with AI

Hyring
Jobseeker using Hyring to search, apply, and prepare with AI

Classes and Structs

Swift gives you two primary building blocks for modeling data: classes and structs. Both can declare properties, methods, and initializers, and both can conform to protocols, but they behave very differently the moment you assign an instance to a new variable or pass it into a function.

Value Types vs Reference Types

A struct is a value type: assigning it to a new variable, or passing it as a function argument, copies its entire contents. A class is a reference type: assigning an instance to a new variable creates a second reference to the exact same object in memory, so mutating through one variable is visible through the other.

  • Structs are copied on assignment and on function calls; classes are shared by reference.
  • Structs receive a free memberwise initializer; classes must define their own init or rely on default values.
  • Structs cannot inherit from another struct; classes support single inheritance from one superclass.
  • Copies of a struct are independent, which makes structs safer to share across threads.
  • Classes support identity comparison with the === and !== operators; structs have no notion of identity.

Struct value semantics

struct Point {
    var x: Int
    var y: Int
}

var a = Point(x: 1, y: 2)
var b = a          // b is a full copy of a
b.x = 99

print("a.x = \(a.x)")   // a.x = 1 (unchanged)
print("b.x = \(b.x)")   // b.x = 99

Class reference semantics

class Counter {
    var value = 0
}

let c1 = Counter()
let c2 = c1          // c2 points to the same instance as c1
c2.value = 42

print("c1.value = \(c1.value)")   // 42, both refer to the same object
print(c1 === c2)                  // true: same identity
Note: Prefer structs by default in Swift. Reach for a class only when you specifically need reference semantics, class inheritance, deinitializers, or interoperability with an Objective-C/Cocoa API that expects a class instance.

Initializers, Computed Properties, and Methods

Both classes and structs can define custom initializers, computed properties that calculate a value on access, and methods that operate on their data. The one difference: a struct method that changes any property must be marked mutating, because struct instance methods otherwise treat self as read-only.

A class with init, computed property, and methods

import Foundation

class BankAccount {
    let owner: String
    private var balance: Double

    init(owner: String, openingBalance: Double = 0) {
        self.owner = owner
        self.balance = openingBalance
    }

    var formattedBalance: String {
        String(format: "$%.2f", balance)
    }

    func deposit(_ amount: Double) {
        balance += amount
    }

    func withdraw(_ amount: Double) throws {
        guard amount <= balance else {
            throw NSError(domain: "BankAccount", code: 1)
        }
        balance -= amount
    }
}

let account = BankAccount(owner: "Priya", openingBalance: 100)
account.deposit(50)
print(account.formattedBalance)   // $150.00
AspectStructClass
KindValue typeReference type
Assignment behaviorCopies the valueShares the reference
InheritanceNot supportedSingle inheritance
Free initializerMemberwise init generated automaticallyNone; you must write your own
Mutating methodsRequire the mutating keyword to change selfNot needed; methods can freely change properties
Identity operator (===)Not applicableSupported
Note: Because structs are value types, a struct stored in a let constant cannot have its properties changed afterward, even if those properties were declared with var. Store it in a var if you need to mutate it later.

Exercise: Swift OOP

What is a core difference between a class and a struct in Swift?