Lazy vars in @Observable classes in Swift
When migrating from the ObservableObject protocol to the @Observable macro, I encountered an issue with using a lazy variable in my observable class. In this post, I’ll explain the problem and show how I resolved it.
Here’s a simplified version of my class using ObservableObject
:
class WalksViewModel: ObservableObject {
let walks = [
Walk(title: "Central Park Loop", difficulty: .easy),
Walk(title: "Mountain Ridge Trail", difficulty: .hard),
Walk(title: "Riverbank Stroll", difficulty: .medium)
]
@Published var sortingIsOn = false
lazy var sortedWalks: [Walk] = {
walks.sorted(
using: KeyPathComparator(\Walk.difficulty)
)
}()
}
This works as expected. However, after updating the class to use the @Observable
macro, the following error appeared: 'lazy' cannot be used on a computed property
.
@Observable
class WalksViewModel {
let walks = [
Walk(title: "Central Park Loop", difficulty: .easy),
Walk(title: "Mountain Ridge Trail", difficulty: .hard),
Walk(title: "Riverbank Stroll", difficulty: .medium)
]
var sortingIsOn = false
// Error: 'lazy' cannot be used on a computed property
lazy var sortedWalks: [Walk] = {
walks.sorted(
using: KeyPathComparator(\Walk.difficulty)
)
}()
}
This happens because the @Observable
macro automatically generates observation logic for all variables in the class, but it cannot synthesize the necessary observation code for a lazy
property.
While searching for a solution, I found this discussion on Swift Forums. I learned that to use lazy variables in observable classes, we can annotate them with @ObservationIgnored
. This tells the observation system to skip synthesizing observation logic for the property.
Here’s how my final solution looks:
@Observable
class WalksViewModel {
let walks = [
Walk(title: "Central Park Loop", difficulty: .easy),
Walk(title: "Mountain Ridge Trail", difficulty: .hard),
Walk(title: "Riverbank Stroll", difficulty: .medium)
]
var sortingIsOn = false
@ObservationIgnored
lazy var sortedWalks: [Walk] = {
walks.sorted(
using: KeyPathComparator(\Walk.difficulty)
)
}()
}
If you're an experienced Swift developer looking to level up your skills, take a look at my book Swift Gems. It offers 100+ advanced Swift tips, from optimizing collections and leveraging generics, to async patterns, powerful debugging techniques, and more - each designed to make your code clearer, faster, and easier to maintain.