Swift Structs Explained: Properties, Methods, and Value Types

Swift structs are one of the most important tools for creating your own types. They let you group related data and behavior into a single reusable unit, and they are used throughout Swift because they are safe, fast, and predictable. In this article, you will learn what structs are, how to define them, how their value semantics work, and how to avoid the most common mistakes developers make when using them.

Quick answer: A Swift struct is a custom value type that can store properties, define methods, and represent related data as one unit. When you copy a struct or assign it to another variable, Swift copies the value instead of sharing the same instance.

Difficulty: Beginner

Helpful to know first: You will understand this better if you already know basic Swift syntax, variables and constants, functions, and simple types like String, Int, and Bool.

1. What Is a Struct?

A struct in Swift is a custom type that groups related values and behavior together. You can think of it as a blueprint for creating values that have named properties and methods.

For example, if you want to represent a user with a name and age, a struct gives you a clean way to keep that data together instead of storing separate unrelated variables.

2. Why Structs Matter

Structs matter because they match the way many real program values behave. A screen size, a date range, a shopping cart item, or a point on a graph is usually best treated as a value, not as a shared object.

Swift encourages using structs by default because they help reduce accidental shared state. When values are copied instead of shared, code becomes easier to reason about and bugs caused by unexpected mutation become less common.

Use structs when:

Structs are not always the right choice. If you need shared identity, inheritance, or reference semantics, a class may be more appropriate. That comparison appears again later in this article because it is one of the most common Swift design decisions.

3. Basic Syntax or Core Idea

The basic syntax of a struct starts with the struct keyword, followed by a name and a body in braces.

Declaring a simple struct

This example defines a Book struct with two stored properties.

struct Book {
var title: String
var pageCount: Int
}

This does not create a book yet. It only defines the shape of the type.

Creating a value from a struct

Because both properties are stored properties and no custom initializer is defined, Swift provides a memberwise initializer automatically.

let swiftBook = Book(title: "Learning Swift", pageCount: 320)

The memberwise initializer lets you pass values for each stored property by name.

Accessing properties

You use dot syntax to read properties.

print(swiftBook.title)
print(swiftBook.pageCount)

This prints the title and page count stored inside the struct value.

Adding methods

Structs can also define methods, which are functions that belong to the type.

struct Rectangle {
var width: Double
var height: Double

func area() -> Double {
return width * height
}
}

The area() method uses the struct's own properties to calculate a result.

4. Step-by-Step Examples

The best way to understand structs is to see them in realistic examples.

Example 1: Storing related user data

Here, a struct groups a user's name and age into one value.

struct User {
var name: String
var age: Int
}

let user = User(name: "Maya", age: 28)
print(user.name)
print(user.age)

This is cleaner than passing separate name and age values all over your code.

Example 2: Using a computed property

A computed property calculates a value instead of storing it directly.

struct Temperature {
var celsius: Double

var fahrenheit: Double {
(celsius * 9 / 5) + 32
}
}

let today = Temperature(celsius: 21)
print(today.fahrenheit)

The struct stores one value and derives another when needed.

Example 3: Mutating a struct

Because structs are value types, methods that change properties must be marked with mutating.

struct Counter {
var count = 0

mutating func increment() {
count += 1
}
}

var counter = Counter()
counter.increment()
print(counter.count)

The mutating keyword tells Swift that the method changes the struct's stored data.

Example 4: Demonstrating value semantics

This example shows one of the most important differences between structs and classes.

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

var start = Point(x: 0, y: 0)
var end = start

end.x = 10

print(start.x)
print(end.x)

Changing end does not change start because assigning a struct creates a copy.

5. Practical Use Cases

Structs are useful in many real projects, especially when modeling values.

Swift's own standard library uses structs heavily. Types like String, Int, Array, and Dictionary are all value-oriented types, which matches Swift's general design style.

6. Common Mistakes

Mistake 1: Forgetting mutating on a method that changes properties

Methods inside a struct are non-mutating by default. If a method changes a stored property, Swift requires the mutating keyword.

Problem: This method changes count without being marked as mutating, so Swift reports an error similar to Cannot assign to property: 'self' is immutable.

struct Counter {
var count = 0

func increment() {
count += 1
}
}

Fix: Mark the method as mutating so Swift knows the struct value will change.

struct Counter {
var count = 0

mutating func increment() {
count += 1
}
}

The corrected version works because mutating allows the method to modify the struct's stored properties.

Mistake 2: Trying to change a struct stored in a constant

Even if the properties inside a struct are declared with var, the whole value becomes immutable when the struct instance is stored in a let constant.

Problem: This code tries to change a property on a constant struct value, so Swift reports an error such as Cannot assign to property: 'item' is a 'let' constant.

struct Task {
var title: String
}

let item = Task(title: "Write article")
item.title = "Review article"

Fix: Use var for the struct value if you need to modify any of its properties.

struct Task {
var title: String
}

var item = Task(title: "Write article")
item.title = "Review article"

The corrected version works because the struct value itself is mutable.

Mistake 3: Expecting two struct variables to share changes

Beginners often assign one struct value to another and expect both names to refer to the same underlying object.

Problem: This code assumes that changing copy will also change original, but structs are copied on assignment.

struct Score {
var points: Int
}

var original = Score(points: 10)
var copy = original
copy.points = 20
print(original.points)

Fix: Treat structs as independent values after assignment. If you need shared identity and shared mutation, consider whether a class is the better model.

struct Score {
var points: Int
}

var original = Score(points: 10)
var copy = original
copy.points = 20

print(original.points) // 10
print(copy.points) // 20

The corrected version works because it reflects the real behavior of value semantics.

7. Best Practices

Use structs by default for simple data models

In Swift, starting with a struct is often the best choice. It gives you predictable value semantics and avoids unnecessary shared state.

struct Product {
var name: String
var price: Double
}

This is a strong default for data that represents a value rather than a shared object.

Keep related behavior inside the struct

If a piece of logic naturally belongs to the data, place it on the struct as a method or computed property. This keeps code organized and easier to read.

struct Circle {
var radius: Double

func area() -> Double {
3.14159 * radius * radius
}
}

This approach keeps the calculation close to the data it depends on.

Prefer constants when values should not change

If a struct instance is not supposed to change, store it in a let constant. This makes your intent clear and prevents accidental mutation.

struct Configuration {
var apiURL: String
}

let config = Configuration(apiURL: "https://api.example.com")

Using a constant here communicates that the configuration value should remain stable.

8. Limitations and Edge Cases

9. Swift Structs vs Classes

Structs and classes are both custom types in Swift, but they are designed for different modeling needs.

FeatureStructClass
SemanticsValue typeReference type
Copy behaviorCopied on assignmentShared reference on assignment
InheritanceNoYes
IdentityNo shared object identityHas reference identity
Common useData values and modelsShared mutable state or inheritance-based designs

Choose a struct when each value should stand on its own. Choose a class when multiple parts of your program need to refer to the same shared object.

struct Position {
var x: Int
}

var a = Position(x: 1)
var b = a
b.x = 5
print(a.x) // 1

With a struct, b becomes a separate copy.

A common Swift guideline is: start with a struct, and switch to a class only when you need reference semantics or inheritance.

10. Practical Mini Project

This mini project creates a simple bank account struct. It stores data, uses methods, and demonstrates mutation clearly.

struct BankAccount {
var owner: String
private(set) var balance: Double

mutating func deposit(amount: Double) {
if amount > 0 {
balance += amount
}
}

mutating func withdraw(amount: Double) {
if amount <= balance {
balance -= amount
}
}

func summary() -> String {
"\(owner) has $\(balance)"
}
}

var account = BankAccount(owner: "Chris", balance: 100)
account.deposit(amount: 50)
account.withdraw(amount: 30)
print(account.summary())

This example shows several useful ideas together: stored properties, access control, mutating methods, and a regular method that returns a formatted description. It is a good example of a value type because each account value can be copied safely and changed independently.

11. Key Points

12. Practice Exercise

Try building your own struct to reinforce the core ideas.

Expected output: Two printed lines showing the same movie before and after the rating change.

Hint: If a method changes a property inside a struct, you need the mutating keyword.

struct Movie {
var title: String
var year: Int
var rating: Double

func description() -> String {
"\(title) (\(year)) - Rating: \(rating)"
}

mutating func updateRating(to newRating: Double) {
rating = newRating
}
}

var movie = Movie(title: "Skyline", year: 2024, rating: 7.2)
print(movie.description())
movie.updateRating(to: 8.1)
print(movie.description())

13. Final Summary

Swift structs are a core part of the language and one of the best tools for modeling data clearly. They let you define custom value types with properties, methods, and computed values, while giving you the safety and predictability of value semantics.

In this article, you learned how to declare structs, create instances, use methods, write mutating behavior, and understand how copying works. You also saw common mistakes such as forgetting mutating or trying to change a struct stored in a constant.

A good next step is to learn more about Swift classes and initializers so you can choose the right custom type for each situation. Once you understand both structs and classes well, designing Swift models becomes much easier.