willSet and didSet are property observers in Swift that allow you to execute code before and after a property value changes. Unlike computed properties, observers do not compute a new value but only react to changes. According to Apple documentation, The Swift Programming Language (2026), observers are indispensable for data validation, interface synchronization, and logging changes in code.
Key Takeaways
willSet and didSet are property observers in Swift, a built-in mechanism for tracking changes to stored properties.
Unlike other languages where manual setter implementation or callback systems are required, Swift provides a declarative syntax for reacting to changes. Observers are added directly after the property declaration and do not require a separate call.
According to Apple Developer Documentation (2026), property observers are supported for stored properties of any class, structure, or enumeration. They do not work with computed properties because those do not store a value — for them, reaction to change is implemented directly in the setter.
willSet is called immediately before assigning a new value to the property. Inside willSet, the implicit parameter newValue is available, containing the value that will be set. At this moment, the current property value has not changed yet — you can read the old value directly through the property.
According to Swift Evolution proposal SE-0001 (2024), willSet provides the ability to perform validation or logging before the actual change. If an exception is thrown in willSet, the new value will not be applied, making observers a data protection mechanism.
didSet is called immediately after assigning a new value. Inside didSet, the implicit parameter oldValue is available, containing the value before the change. At this point, the property already contains the new value, and you can compare it with the old one.
According to Swift by Sundell (2025), didSet is the most popular observer because it is most often needed for post-processing: updating UI, recalculating dependent fields, or sending data to the server after a change.
Property observers are declared immediately after the property using curly braces. The minimal syntax requires only one observer, but you can declare both.
var score: Int = 0 {
willSet {
print("Score will change to \(newValue)")
}
didSet {
print("Score changed from \(oldValue) to \(score)")
}
}
Both observers are optional — you can specify only willSet or only didSet. For willSet you can rename newValue by specifying a name in parentheses.
var username: String = "guest" {
willSet(newName) {
print("About to set \(newName)")
}
didSet(oldName) {
print("Was \(oldName), now \(username)")
}
}
According to Swift Language Guide (2026), renaming parameters improves code readability, especially when the property and observers are used in a large project with long names.
The order of execution is strictly defined: first willSet (old value is available), then assignment, then didSet (new value is available).
class Temperature {
var celsius: Double = 0.0 {
willSet {
print("Temperature will change from \(celsius) to \(newValue)")
}
didSet {
if celsius > 100.0 {
print("Boiling point exceeded!")
}
}
}
}
An important limitation: observers are not called during property initialization when creating an instance. Inside init, assigning a value does not trigger willSet and didSet — this prevents unwanted side effects at the construction stage.
According to the Apple Swift Blog (2025), this behavior differs from many other languages where setters are called even in constructors. Swift chooses safety: observers only start working after the object initialization is complete.
Changing a property inside didSet can lead to repeated observer calls. Swift does not block recursion — the programmer must control it manually.
var counter: Int = 0 {
didSet {
if counter < 5 {
counter += 1
}
}
}
Such code will create total recursion with stack overflow if no exit condition is provided. According to Stack Overflow Swift Community (2025), this is one of the most common mistakes beginners make when working with property observers.
Structures support willSet and didSet for stored properties without restrictions. It is important to remember that structures are value types, and modifying a property inside a mutating method also triggers observers.
struct Point {
var x: Double = 0.0 {
didSet {
print("X changed to \(x)")
}
}
var y: Double = 0.0 {
didSet {
print("Y changed to \(y)")
}
}
}
var point = Point()
point.x = 5.0
Property observers are used in Swift projects for a wide range of tasks: from UI synchronization to data validation and logging.
didSet allows you to roll back or correct an invalid value immediately after it is set. This replaces cumbersome setters in Objective-C and ensures data integrity at the model level.
var age: Int = 0 {
didSet {
if age < 0 || age > 150 {
age = oldValue
}
}
}
When a related property changes, you can automatically update interface elements without a separate update method call.
var userName: String = "" {
didSet {
nameLabel.text = userName
}
}
willSet is convenient for logging for debugging or auditing purposes. You can record the time and the new value before it is applied, ensuring the log contains the original data for analysis.
According to objc.io (2025), property observers are especially useful in architectures with unidirectional data flow, where every property change is recorded for subsequent state reproduction.
Computed properties calculate a value on the fly and have no storage, while willSet and didSet work on a stored property with an actual value.
| Characteristic | Property Observers | Computed Properties |
|---|---|---|
| Stores value | Yes | No |
| Executes code on change | Yes | No |
| Declaration type | var | var (get/set) |
| Access parameters | newValue, oldValue | newValue (in set) |
| Initialization | Requires initial value | Not required |
The key difference: a computed property calculates a value on each access, while a property observer reacts to a change of an existing value. The choice between them is dictated by semantics — if the property is derived from other data, use computed; if it is an independent value whose changes need to be observed, use willSet/didSet.
The most common mistake is recursive didSet calls without an exit condition. Each property change inside didSet triggers the observer again, leading to an infinite loop.
The second common mistake is attempting to use observers on let properties. The Swift compiler will throw an error because let is a constant.
The third mistake is ignoring that the observer is not called during initialization. Developers expecting willSet to fire inside init get unexpected behavior.
The fourth problem is applying observers to properties in extensions. Swift prohibits adding willSet/didSet to stored properties in extensions.
According to Ray Wenderlich (2025), understanding these limitations helps avoid bugs at early stages and makes Swift code more predictable.
Frequently Asked Questions
Yes, each observer is optional. You can declare only willSet, only didSet, or both at once.
No, Swift prohibits adding willSet and didSet in extensions for stored properties. Observers are declared only in the original type definition.
No, observers are not called during initialization. This is a protective mechanism that prevents side effects at the object construction stage.
willSet is a stored property observer that executes before the value changes. A setter in a computed property is a way to calculate a new value, not to observe an existing one.
A repeated didSet call will cause recursion. Without an exit condition, this leads to stack overflow and program termination.
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