Struct is a value type in the Swift language, instances of which are copied when passed between parts of code. Unlike classes, structures do not support inheritance, but they implement protocols, contain properties and methods, and provide predictable memory management without ARC. According to the Swift Programming Language Guide, 2026, struct is a fundamental building block of Swift — even standard types Int, String, Array and Dictionary are implemented as structures. The language recommends structures as the preferred choice for data modeling.
Key Takeaways
Struct (structure) is a composite data type in Swift that groups related properties and methods into a single entity. Unlike classes, structures are value types: when passed to a function or assigned to a new variable, an independent copy of the structure is created, not a reference to the original object.
Swift uses structures for all primitive types: Int, Double, String, Bool, Array, Dictionary and Set. This means that even a basic Int behaves as a structure — a copy is created upon assignment. Developers can define their own structures with any set of properties and methods.
According to Swift Evolution (SE-0143), the decision to implement standard types as structures is driven by performance and predictability. Value types do not create reference cycles, do not require ARC reference counting, and guarantee that modifying a copy will not affect the original — this is critically important for data immutability in multithreaded scenarios.
Value type semantics is the key difference between struct and class. When you assign a structure to a new variable or pass it to a function, Swift creates an independent copy of all data. Any changes to the copy do not affect the original, eliminating the side effects typical of reference types.
// Example of value type semantics
struct Point {
var x: Double
var y: Double
}
var p1 = Point(x: 10, y: 20)
var p2 = p1 // p2 is an independent copy of p1
p2.x = 99 // Only p2 changes
print(p1.x) // 10 — p1 unchanged
print(p2.x) // 99
Swift uses Copy-on-Write (COW) to optimize copying. If multiple variables reference the same structure but none of them modifies the data, no actual copying occurs. Swift shares memory between variables until the first mutation — then a real copy is created. This prevents excessive allocate operations and speeds up work with collections.
By default, structure methods cannot modify the structure’s properties — Swift requires the explicit mutating keyword for methods that make changes. This restriction protects against accidental mutation and makes the code predictable: if a method is not marked as mutating, you are guaranteed not to change the structure.
When you add the mutating keyword before a method, Swift gains the ability to write new values to the structure’s properties. In fact, the method can even completely replace the structure instance with a new one via self =. This mechanism is used, for example, in Option and Result types.
// Struct with mutating method
struct Counter {
private var value: Int = 0
// Mutating method — can modify properties
mutating func increment() {
value += 1
}
// Mutating method can replace self entirely
mutating func reset() {
self = Counter()
}
// Non-mutating method — read only
func currentValue() -> Int {
return value
}
}
var counter = Counter()
counter.increment()
print(counter.currentValue()) // 1
counter.reset()
print(counter.currentValue()) // 0
Rules for mutating: the structure must be declared with var, not let — a constant structure cannot call a mutating method. The compiler checks this at build time: attempting to call a mutating method on a let-constant will result in a compilation error.
The choice between struct and class is one of the fundamental decisions in Swift. Both types can contain properties, methods, initializers and implement protocols, but they have fundamental differences in memory semantics, inheritance and lifecycle management.
| Feature | struct | class |
|---|---|---|
| Type | Value type (copied) | Reference type (reference) |
| Inheritance | Not supported | Supported |
| ARC / reference counting | Not required | ARC required |
| Deinitialization | Not supported | Supports deinit |
| Property mutation in constants | Only via var | Possible via let (reference is constant) |
| Type casting | Not supported | Supported |
| Storage in collections | Stored directly (value) | Stored as reference (pointer) |
Structures are preferred when data does not require inheritance, should not have shared identity (e.g., coordinates, sizes, configuration) and are passed between modules. Classes are chosen for UI components (UIView, UIViewController), singletons and objects with shared identity.
Apple recommends using struct as the default type for data modeling in Swift. Structures are suitable for most scenarios due to predictable copy semantics and no overhead from reference counting. Let’s look at typical cases where struct is the optimal choice.
If an entity contains data without needing inheritance (Product, User, Order, Point), use struct. The compiler automatically generates a memberwise initializer — you don’t need to write init manually. Equatable and Hashable are also automatically implemented for structures whose properties all conform to these protocols.
For configurations, settings and flags that don’t change after creation, struct is preferable to class. A constant (let) structure guarantees the immutability of all nested fields — in a class this only applies to the reference, not to the object’s contents.
Structures are safe in multithreaded environments due to value semantics. Each thread gets an independent copy of the data and does not affect other threads. Data races between threads are impossible for value types, making struct the preferred choice for models in SwiftUI (ObservableObject requires class, but @State uses struct).
// Example of struct usage for data model
struct User: Codable, Identifiable {
let id: UUID
var name: String
var email: String
var isPremium: Bool
// Computed property — non-mutating
var displayName: String {
isPremium ? "\(name) ⭐️" : name
}
}
// Automatic memberwise initializer
let user = User(
id: UUID(),
name: "Alice",
email: "alice@example.com",
isPremium: true
)
// Copying is safe for multi-threading
var userCopy = user
userCopy.isPremium = false
// user.isPremium remains true
Use class when you need inheritance (UIKit/AppKit components), shared identity (delegate, observer) or controlled object lifecycle (deinit). For everything else — use struct.
Frequently Asked Questions
Struct in Swift is a value type that is copied when passed between parts of code. Structures can contain properties, methods, initializers and implement protocols. Basic Swift types (Int, String, Array) are implemented as structures.
Struct is a value type (copied on assignment), does not support inheritance and does not require ARC. Class is a reference type (passed by reference), supports inheritance, deinitialization and reference counting. Developers recommend struct as the default type.
Mutating is a keyword that indicates a structure method can modify its properties. Without mutating, the compiler forbids field modification. Mutating methods can only be called on variables declared with var, not let.
Copy-on-Write (COW) is a Swift optimization for structures where actual data copying is deferred until the first mutation. As long as all variables only read the structure, they share a single memory area. This improves performance when working with large collections.
Use struct for data models without inheritance, configurations, DTOs and multithreaded scenarios. Use class for UIKit/AppKit UI components, singletons, entities with shared identity (delegate, observer) and objects requiring deinitialization.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also