In the last article we built our first structs with stored properties โ values that sit in memory and hold data directly. But Swift gives us a second, more dynamic option: computed properties โ values that are calculated every time they're accessed, rather than stored. ๐ฅ
Think of it like this: a stored property is like a lunchbox that holds your food. A computed property is like a vending machine โ every time you press the button, it calculates and delivers the result fresh.
The Problem With Stored Properties Alone
Let's say we're tracking a ninja's chakra usage:
struct Ninja {
let name: String
var chakraRemaining: Int
}
var naruto = Ninja(name: "Naruto", chakraRemaining: 1000)
naruto.chakraRemaining -= 300
print(naruto.chakraRemaining) // 700
naruto.chakraRemaining -= 200
print(naruto.chakraRemaining) // 500
This works, but we're losing important information โ we started with 1000 chakra, but once we start subtracting, we've lost track of the original amount. If someone asks "how much chakra has Naruto used?", we can't answer.
Enter Computed Properties
Instead of storing chakraRemaining directly, we can store the original amount and used amount separately, then compute what's remaining:
struct Ninja {
let name: String
var chakraTotal = 1000
var chakraUsed = 0
var chakraRemaining: Int {
chakraTotal - chakraUsed
}
}
Now chakraRemaining is a computed property โ it looks like a regular property when you read it, but behind the scenes Swift is running code to calculate the value every time:
var naruto = Ninja(name: "Naruto", chakraTotal: 1000)
naruto.chakraUsed += 300
print(naruto.chakraRemaining) // 700 โ calculated automatically!
naruto.chakraUsed += 200
print(naruto.chakraRemaining) // 500 โ always up to date!
Notice: we never manually update chakraRemaining. It's always calculated fresh from chakraTotal and chakraUsed, so it's always accurate. ๐
Getters and Setters
Right now our computed property is read-only โ we can read chakraRemaining, but we can't write to it directly. If you tried:
naruto.chakraRemaining = 400 // โ won't compile
Swift would complain because it doesn't know how to handle that assignment. Should it change chakraTotal? Should it change chakraUsed? We haven't told it.
To make a computed property writable, we need to add both a getter (code that reads) and a setter (code that writes):
struct Ninja {
let name: String
var chakraTotal = 1000
var chakraUsed = 0
var chakraRemaining: Int {
get {
chakraTotal - chakraUsed
}
set {
chakraTotal = chakraUsed + newValue
}
}
}
A few things to notice:
-
get { }โ the code that runs when you readchakraRemaining -
set { }โ the code that runs when you write tochakraRemaining -
newValueโ automatically provided by Swift insideset, representing whatever value was assigned
So if someone sets naruto.chakraRemaining = 400, Swift runs the setter with newValue = 400, and updates chakraTotal accordingly.
Here it is in action:
var naruto = Ninja(name: "Naruto", chakraTotal: 1000)
naruto.chakraUsed += 300
print(naruto.chakraRemaining) // 700
naruto.chakraRemaining = 400 // using the setter
print(naruto.chakraTotal) // 700 โ updated automatically!
Stored vs Computed โ Which Should You Use?
Now that you know both types exist, when do you reach for each one?
Use a stored property when:
- The value doesn't depend on other properties
- The property is read frequently and the value rarely changes
- You want to store information that comes from outside (user input, API data, etc.)
struct Hero {
let name: String // stored โ doesn't change
var level: Int // stored โ set once, updated occasionally
}
Use a computed property when:
- The value depends on other properties and should always stay in sync
- The property is read rarely, so calculating it on demand is fine
- You want the value to automatically reflect the current state
struct Hero {
var baseAttack: Int
var bonusAttack: Int
var totalAttack: Int { // computed โ always baseAttack + bonusAttack
baseAttack + bonusAttack
}
}
The key insight: computed properties are great for derived values โ things that can be calculated from data you already have. Instead of manually keeping two values in sync, you store the source data and let the computed property do the math automatically.
A Quick Note on Performance
Computed properties are recalculated every time you access them. For simple calculations like chakraTotal - chakraUsed, that's completely fine โ it's almost instant.
But if your computed property did something expensive (like sorting a massive array), calling it thousands of times could slow things down. In those cases, a stored property (updated when needed) would be the smarter choice.
For everything you'll build early on, computed properties are perfectly efficient โ just good to keep in the back of your mind as projects grow. ๐ธ
Why This Matters for SwiftUI
Computed properties are absolutely everywhere in SwiftUI. In fact, the very first thing you'll write in any SwiftUI project is this:
struct ContentView: View {
var body: some View {
Text("Hello, world!")
}
}
That body property? It's a computed property. Every time SwiftUI needs to know what to display, it calls the body getter and gets back a fresh view. You're already using computed properties before you even know it! ๐
Wrap Up
| Concept | What It Means |
|---|---|
| Stored property | A value held in memory, assigned directly |
| Computed property | A value calculated on the fly using code |
get |
The code that runs when you read a computed property |
set |
The code that runs when you write to a computed property |
newValue |
The value being assigned, automatically available inside set
|
This article was written by me; AI was used to improve grammar and readability.
Top comments (0)