- July 30, 2025
- Mins Read
In Swift, a struct is a value type that you define with the struct
keyword. You can give it stored properties, computed properties, initializers, methods, subscripts, and conformances to protocols.
// Define a simple struct
struct Person {
// Stored properties
var name: String
var age: Int
// Computed property
var description: String {
"\(name) is \(age) years old"
}
// Custom initializer (optional—Swift generates one automatically if you don't write it)
init(name: String, age: Int) {
self.name = name
self.age = age
}
// Instance method
func greet() {
print("Hello, my name is \(name).")
}
}
// Usage
var alice = Person(name: "Alice", age: 30)
print(alice.description) // Alice is 30 years old
alice.greet() // Hello, my name is Alice.
person.name
, person.age
.let point = (x: 3, y: 4)
print(point.x, point.y)
let pair = ("hello", 42)
print(pair.0, pair.1)
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
struct Calculator {
func multiply(_ a: Int, _ b: Int) -> Int {
return a * b
}
}
Methods have access to self
and can read or modify the instance’s properties (if allowed).
mutating
?Because structs (and enums) are value types, methods that change their stored properties must be marked mutating
. This signals that the method will modify the instance itself, rather than just reading from it.
struct Counter {
var count: Int = 0
// Without `mutating` this would be a compile-time error:
mutating func increment() {
count += 1
}
}
var c = Counter()
c.increment()
print(c.count) // 1
Attempting to modify count
inside a non-mutating method would not compile.
// Define a struct Point and test its properties
struct Point {
var x: Int
var y: Int
func movedBy(dx: Int, dy: Int) -> Point {
Point(x: x + dx, y: y + dy)
}
}
// Test creation and method
let p = Point(x: 2, y: 3)
let p2 = p.movedBy(dx: 5, dy: -1)
assert(p2.x == 7 && p2.y == 2)
print("Test Passed: Point moved correctly to (\(p2.x), \(p2.y))")
Expected output:
Test Passed: Point moved correctly to (7, 2)
// Define a struct BankAccount with a mutating deposit
struct BankAccount {
var balance: Double
mutating func deposit(_ amount: Double) {
balance += amount
}
}
// Test the mutating method
var account = BankAccount(balance: 100.0)
account.deposit(50.0)
assert(account.balance == 150.0)
print("Test Passed: balance after deposit is \(account.balance)")
Expected output:
Test Passed: balance after deposit is 150.0
A computed property doesn’t store a value directly. Instead, it defines a getter (and optionally a setter) that calculates its value on the fly based on other properties or logic.
struct Rectangle {
var width: Double
var height: Double
// Computed property
var area: Double {
return width * height
}
// Computed property with setter
var perimeter: Double {
get {
return 2 * (width + height)
}
set(newPerimeter) {
// Adjust width proportionally (for example purposes)
let ratio = width / (width + height)
let half = newPerimeter / 2
width = half * ratio
height = half * (1 - ratio)
}
}
}
get { … }
if it’s a single expression.set { … }
or set(newValue) { … }
.area
of a shape, fullName
combining firstName
and lastName
.Rule of thumb: if you find yourself writing didSet
or willSet
to maintain another property in sync, consider making that other property a computed one instead.
Paste this into a Swift playground or project to verify your computed properties work as expected:
// Define a struct with computed properties
struct Circle {
var radius: Double
// Computed area
var area: Double {
Double.pi * radius * radius
}
// Computed diameter (getter + setter)
var diameter: Double {
get {
radius * 2
}
set {
radius = newValue / 2
}
}
}
// Test 1: area calculation
let c1 = Circle(radius: 3)
let expectedArea = Double.pi * 9
assert(abs(c1.area - expectedArea) < 1e-10)
print("Test 1 Passed: area is \(c1.area)")
// Test 2: diameter getter
assert(c1.diameter == 6)
print("Test 2 Passed: diameter getter == \(c1.diameter)")
// Test 3: diameter setter updates radius
var c2 = Circle(radius: 1)
c2.diameter = 10
assert(abs(c2.radius - 5) < 1e-10)
print("Test 3 Passed: radius after setting diameter == \(c2.radius)")
Expected output:
Test 1 Passed: area is 28.2743338823081
Test 2 Passed: diameter getter == 6.0
Test 3 Passed: radius after setting diameter == 5.0
PermissionsSwiftUI displays and handles permissions in SwiftUI. It is largely inspired by SPPermissions. The UI is highly customizable and resembles an Apple style. ...
Introduction PagerTabStripView is the first pager view built in pure SwiftUI. It provides a component to create interactive pager views ...
1. Taking Action When a Property Changes: Property Observers Swift lets you observe and respond to changes in a property’s ...