willSet and didSet in Swift: what they are, syntax and how observers work

Author: IT Sectr Published: 2026-06-20 Reading time: 9 min

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 is called before saving a new property value
  • didSet is called after saving a new value
  • newValue is an implicit parameter in willSet containing the new value
  • oldValue is an implicit parameter in didSet containing the old value
  • Observers do not work during initialization and inside init

What are willSet and didSet in Swift?

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.

When willSet is called

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.

When didSet is called

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 observer syntax

Property observers are declared immediately after the property using curly braces. The minimal syntax requires only one observer, but you can declare both.

swift
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.

swift
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.

How willSet and didSet work

The order of execution is strictly defined: first willSet (old value is available), then assignment, then didSet (new value is available).

swift
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.

Nested calls and recursion

Changing a property inside didSet can lead to repeated observer calls. Swift does not block recursion — the programmer must control it manually.

swift
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.

Observers for structure properties

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.

swift
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

Using observers in real projects

Property observers are used in Swift projects for a wide range of tasks: from UI synchronization to data validation and logging.

Value validation

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.

swift
var age: Int = 0 {
    didSet {
        if age < 0 || age > 150 {
            age = oldValue
        }
    }
}

UI synchronization

When a related property changes, you can automatically update interface elements without a separate update method call.

swift
var userName: String = "" {
    didSet {
        nameLabel.text = userName
    }
}

Change logging

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.

Comparison with computed properties

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.

CharacteristicProperty ObserversComputed Properties
Stores valueYesNo
Executes code on changeYesNo
Declaration typevarvar (get/set)
Access parametersnewValue, oldValuenewValue (in set)
InitializationRequires initial valueNot 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.

Common mistakes when using

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

Can I use willSet without didSet?

Yes, each observer is optional. You can declare only willSet, only didSet, or both at once.

Do observers work in extensions?

No, Swift prohibits adding willSet and didSet in extensions for stored properties. Observers are declared only in the original type definition.

Are observers called when changing a property inside init?

No, observers are not called during initialization. This is a protective mechanism that prevents side effects at the object construction stage.

How is willSet different from a setter in a computed property?

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.

What happens when a property is changed inside didSet?

A repeated didSet call will cause recursion. Without an exit condition, this leads to stack overflow and program termination.

Summary

  • willSet is an observer executed before a property changes, with access to newValue
  • didSet is an observer executed after a property changes, with access to oldValue
  • Syntax — observers are declared in curly braces after the property declaration
  • Initialization — observers do not work inside init and when setting a default value
  • Usage — validation, UI synchronization, logging, change audit
  • Recursion — changing a property inside didSet requires an explicit exit condition
  • Computed — do not confuse with computed properties: observers observe, computed calculate

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.

Discuss the project

Read also