Lazy Initialization
Lazy Initialization postpones work until first use. Swift's lazy var is a direct implementation for instance properties, but it does not solve concurrency or lifetime design by itself.
When it helps in iOS
A notes app has an optional local search screen. Building an index during app launch slows startup even for users who never open search.
Original example: create a search index on demand
import Foundation
struct Note {
let id: UUID
let text: String
}
final class SearchIndex {
private let notes: [Note]
init(notes: [Note]) {
self.notes = notes
// A production index could tokenize text here.
}
func find(_ query: String) -> [Note] {
notes.filter { $0.text.localizedCaseInsensitiveContains(query) }
}
}
@MainActor
final class NotesStore {
private let notes: [Note]
init(notes: [Note]) { self.notes = notes }
lazy var searchIndex = SearchIndex(notes: notes)
}
let store = NotesStore(notes: [Note(id: UUID(), text: "Grocery list")])
// The index is created when store.searchIndex is first accessed.The store can initialize quickly; the index cost moves to the first search.
Production decisions
If first-use latency is noticeable, prewarm the index after launch or build it in a background task and show a loading state. The store is main-actor isolated so simultaneous access does not race through initialization. Rebuild or update the index when notes change; this example uses an immutable note snapshot.
Observe when work happens
NotesStore stores notes immediately but does not construct SearchIndex in its initializer. The first access to searchIndex runs the lazy initializer using the stored notes; subsequent accesses return the same index. This can shorten launch time when search is rarely opened. The cost has not disappeared: it has moved to first use, which may now be visible to the user.
From example to an iOS search screen
The screen can show a small loading state while an index is built in a background task, then enable search. If most users open search immediately, eager construction or prewarming during idle time may feel faster. When notes change, the index must be updated or rebuilt. Because the sample captures an immutable note array, it is a snapshot, not a live index. Keep index creation away from the main actor if tokenization is expensive.
Failure modes and verification
Test that constructing the store does not build the index, that first access builds it once, and that later note changes are reflected through a documented update path. Swift lazy var on a shared object is not automatically safe for concurrent first access; isolate the owner or synchronize initialization. Use lazy creation for measured expensive work, not as a default for every property.