Swift Structures Basics
Introduction
Structures (or "structs") are one of the foundational building blocks in Swift programming. They allow you to create custom data types by grouping related values and behaviors together. Unlike classes in other languages, Swift structures are value types, making them particularly useful when you want to ensure data is copied rather than referenced.
In this tutorial, we'll explore the basics of Swift structures, how to define them, and how to use them effectively in your code. This knowledge forms an essential part of writing clean, efficient Swift applications.
What Are Structures?
A structure in Swift is a custom data type that encapsulates data and related functionality. Structures are particularly useful when you want to:
- Group related properties and methods
- Create immutable values
- Ensure data is copied rather than referenced
- Create reusable components with consistent behavior
Defining a Structure
Let's start by creating a simple structure:
struct Person {
// Properties
var name: String
var age: Int
// Methods
func describe() -> String {
return "This person is \(name) who is \(age) years old."
}
}
This Person
structure has:
- Two properties:
name
(a String) andage
(an Int) - One method:
describe()
that returns a String description of the person
Creating Instances of a Structure
Once you've defined a structure, you can create instances of it:
// Create an instance of Person
let john = Person(name: "John", age: 25)
// Access properties
print(john.name) // Output: John
print(john.age) // Output: 25
// Call methods
print(john.describe()) // Output: This person is John who is 25 years old.
Notice that Swift automatically provides a memberwise initializer for structures, which allows you to create new instances by specifying values for each property.
Mutability in Structures
Structures in Swift are value types, which means they're copied when assigned to variables or passed as function arguments. This has important implications for mutability:
struct Counter {
var count: Int = 0
mutating func increment() {
count += 1
}
}
// With a variable instance, you can modify properties
var counter1 = Counter()
counter1.count = 10
counter1.increment()
print(counter1.count) // Output: 11
// With a constant instance, you cannot modify properties
let counter2 = Counter()
// counter2.count = 10 // Error: Cannot assign to property
// counter2.increment() // Error: Cannot use mutating member on immutable value
Notice the mutating
keyword before the increment()
method. This is required for any method that changes properties within the structure.
Properties in Structures
Swift structures can have different types of properties:
Stored Properties
These are variables or constants stored as part of the structure:
struct Rectangle {
var width: Double
var height: Double
}
Computed Properties
These are properties that calculate their value rather than storing it:
struct Rectangle {
var width: Double
var height: Double
// Computed property
var area: Double {
return width * height
}
}
let rectangle = Rectangle(width: 10.0, height: 5.0)
print(rectangle.area) // Output: 50.0
Property Observers
These are blocks of code that execute when a property's value changes:
struct Progress {
var task: String
var percentage: Double {
didSet {
print("\(task) is now \(percentage)% complete")
}
}
}
var progress = Progress(task: "Loading data", percentage: 0)
progress.percentage = 30 // Output: Loading data is now 30% complete
progress.percentage = 100 // Output: Loading data is now 100% complete
Custom Initializers
Although Swift provides a memberwise initializer automatically, you can define custom initializers:
struct Temperature {
var celsius: Double
// Custom initializer
init(fahrenheit: Double) {
celsius = (fahrenheit - 32) / 1.8
}
// Another custom initializer
init(kelvin: Double) {
celsius = kelvin - 273.15
}
}
let temp1 = Temperature(celsius: 25)
let temp2 = Temperature(fahrenheit: 98.6)
let temp3 = Temperature(kelvin: 298.15)
print(temp1.celsius) // Output: 25.0
print(temp2.celsius) // Output: 37.0
print(temp3.celsius) // Output: 25.0
Practical Example: Building a Task Manager
Let's build a simple task management system using structures:
struct Task {
var title: String
var isComplete: Bool = false
mutating func markComplete() {
isComplete = true
}
}
struct TaskList {
var name: String
var tasks: [Task] = []
mutating func add(task: Task) {
tasks.append(task)
}
mutating func completeTask(at index: Int) {
if index < tasks.count {
tasks[index].markComplete()
}
}
func printStatus() {
print("Task List: \(name)")
for (index, task) in tasks.enumerated() {
let status = task.isComplete ? "✓" : "□"
print("\(index + 1). [\(status)] \(task.title)")
}
}
}
// Usage example
var workTasks = TaskList(name: "Work Tasks")
workTasks.add(task: Task(title: "Finish Swift tutorial"))
workTasks.add(task: Task(title: "Prepare presentation"))
workTasks.add(task: Task(title: "Send weekly report"))
workTasks.printStatus()
// Output:
// Task List: Work Tasks
// 1. [□] Finish Swift tutorial
// 2. [□] Prepare presentation
// 3. [□] Send weekly report
workTasks.completeTask(at: 0)
workTasks.printStatus()
// Output:
// Task List: Work Tasks
// 1. [✓] Finish Swift tutorial
// 2. [□] Prepare presentation
// 3. [□] Send weekly report
This example shows how structures can be composed together to build a simple but effective system.
When to Use Structures
In Swift, you should prefer structures over classes when:
- You primarily need to encapsulate a few relatively simple data values
- You expect the encapsulated values to be copied rather than referenced
- Any properties stored by the structure are themselves value types
- You don't need inheritance from another type
Apple's guidance is to start with structures by default and only use classes when you specifically need reference semantics.
Summary
In this tutorial, we've covered the basics of Swift structures, including:
- How to define structures with properties and methods
- Creating and working with structure instances
- Understanding mutability in structures
- Different types of properties (stored, computed, and observers)
- Custom initializers
- A practical example building a task management system
Structures are a powerful feature in Swift that help you write safer, more predictable code. By understanding how to use them effectively, you're well on your way to becoming a proficient Swift programmer.
Additional Resources
Exercises
-
Create a
Book
structure with properties for title, author, and pages. Add a method that returns whether the book is considered "long" (more than 300 pages). -
Design a
BankAccount
structure with properties for account number and balance. Add methods to deposit and withdraw money, ensuring the balance can't go below zero. -
Build a
ShoppingCart
structure that contains an array ofItem
structures. Implement methods to add items, remove items, and calculate the total price. -
Create a
Point
structure to represent a 2D point. Add a method to calculate the distance between two points. -
Implement a
Temperature
structure that can convert between Celsius, Fahrenheit, and Kelvin scales using computed properties.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)