Swift Structures

Value types for modeling data and behavior

🧱 What are Swift Structures?

Structures are value types that encapsulate data and functionality. They're copied when assigned or passed around, making them safe and predictable. Structs are Swift's preferred way to model simple data.


// Basic structure definition
struct Point {
    var x: Double
    var y: Double
    
    func distance(to other: Point) -> Double {
        let dx = x - other.x
        let dy = y - other.y
        return sqrt(dx * dx + dy * dy)
    }
}

let point1 = Point(x: 0, y: 0)
let point2 = Point(x: 3, y: 4)
print(point1.distance(to: point2)) // Output: 5.0
                                    

Key Structure Features

📋

Value Types

Structs are copied when assigned

var point1 = Point(x: 1, y: 2)
var point2 = point1
point2.x = 5
print(point1.x) // Still 1
🔧

Automatic Initializers

Free memberwise initializers

struct Person {
    var name: String
    var age: Int
}
let person = Person(name: "Alice", age: 30)
🔄

Mutating Methods

Methods that modify struct properties

struct Counter {
    var count = 0
    mutating func increment() {
        count += 1
    }
}
💡

Computed Properties

Properties that calculate values

struct Circle {
    var radius: Double
    var area: Double {
        return .pi * radius * radius
    }
}

🔹 Basic Structure Example

Here's a simple structure representing a book:

struct Book {
    var title: String
    var author: String
    var pages: Int
    var isRead: Bool = false
    
    var description: String {
        return "\(title) by \(author) (\(pages) pages)"
    }
    
    mutating func markAsRead() {
        isRead = true
        print("Marked '\(title)' as read")
    }
    
    func recommendationLevel() -> String {
        if pages < 200 {
            return "Quick read"
        } else if pages < 400 {
            return "Standard read"
        } else {
            return "Long read"
        }
    }
}

var myBook = Book(title: "Swift Programming", author: "Apple", pages: 350)
print(myBook.description)
print("Recommendation: \(myBook.recommendationLevel())")
myBook.markAsRead()

Output:

Swift Programming by Apple (350 pages)

Recommendation: Standard read

Marked 'Swift Programming' as read

🔹 Mutating Methods

Use mutating methods to modify struct properties:

struct Temperature {
    var celsius: Double
    
    var fahrenheit: Double {
        get {
            return celsius * 9/5 + 32
        }
        set {
            celsius = (newValue - 32) * 5/9
        }
    }
    
    mutating func increaseByCelsius(_ amount: Double) {
        celsius += amount
    }
    
    mutating func increaseByFahrenheit(_ amount: Double) {
        fahrenheit += amount
    }
}

var temp = Temperature(celsius: 20.0)
print("Initial: \(temp.celsius)°C, \(temp.fahrenheit)°F")

temp.increaseByCelsius(5.0)
print("After +5°C: \(temp.celsius)°C, \(temp.fahrenheit)°F")

temp.increaseByFahrenheit(10.0)
print("After +10°F: \(temp.celsius)°C, \(temp.fahrenheit)°F")

Output:

Initial: 20.0°C, 68.0°F

After +5°C: 25.0°C, 77.0°F

After +10°F: 30.56°C, 87.0°F

🔹 Custom Initializers

Create custom initializers for more control over struct creation:

struct Rectangle {
    var width: Double
    var height: Double
    
    // Custom initializer
    init(width: Double, height: Double) {
        self.width = max(0, width)  // Ensure positive values
        self.height = max(0, height)
    }
    
    // Convenience initializer for squares
    init(side: Double) {
        self.init(width: side, height: side)
    }
    
    // Initializer with default values
    init() {
        self.init(width: 1.0, height: 1.0)
    }
    
    var area: Double {
        return width * height
    }
    
    var isSquare: Bool {
        return width == height
    }
}

let rect1 = Rectangle(width: 5.0, height: 3.0)
let square = Rectangle(side: 4.0)
let defaultRect = Rectangle()

print("Rectangle area: \(rect1.area)")
print("Square area: \(square.area), is square: \(square.isSquare)")
print("Default area: \(defaultRect.area)")

Output:

Rectangle area: 15.0

Square area: 16.0, is square: true

Default area: 1.0

🔹 Value Semantics

Structures demonstrate value semantics - each instance is independent:

struct Player {
    var name: String
    var score: Int
    
    mutating func addPoints(_ points: Int) {
        score += points
        print("\(name) scored \(points) points! Total: \(score)")
    }
}

var player1 = Player(name: "Alice", score: 100)
var player2 = player1  // Creates a copy

player1.name = "Alice Smith"
player2.addPoints(50)

print("Player 1: \(player1.name), Score: \(player1.score)")
print("Player 2: \(player2.name), Score: \(player2.score)")

Output:

Alice scored 50 points! Total: 150

Player 1: Alice Smith, Score: 100

Player 2: Alice, Score: 150

🔹 When to Use Structures

Structures are ideal for many common programming tasks:

Perfect for Structures:

  • Simple data models: Points, sizes, colors, coordinates
  • Value semantics: When you want independent copies
  • Mathematical objects: Vectors, matrices, complex numbers
  • Configuration objects: Settings, preferences, options
  • Small collections: Ranges, pairs, tuples

Consider Classes Instead When:

  • You need inheritance
  • You need reference semantics (shared instances)
  • You need deinitializers
  • You need identity checking (===)

🧠 Test Your Knowledge

What happens when you assign one struct to another variable?