What are property observers in Swift? How to use willSet and didSet?
Property observers in Swift are used to monitor and respond to changes in property values. When a property value is set, property observers are triggered, allowing you to execute custom code before and after the value changes.
Types of Property Observers:
-
willSet:
- Called before the new value is stored
- Can access the new value (via default parameter name newValue)
- Can perform validation or preparation before setting the new value
- Example:
swift
class StepCounter { var totalSteps: Int = 0 { willSet(newTotalSteps) { print("About to set totalSteps to \(newTotalSteps)") } } }
-
didSet:
- Called after the new value is stored
- Can access the old value (via default parameter name oldValue)
- Can perform updates or notifications after the value changes
- Example:
swift
class StepCounter { var totalSteps: Int = 0 { didSet { print("Added \(totalSteps - oldValue) steps") } } }
Complete Example:
swiftclass TemperatureMonitor { var temperature: Double { willSet { print("Temperature will change from \(temperature) to \(newValue)") if newValue > 100 { print("Warning: High temperature!") } } didSet { print("Temperature changed from \(oldValue) to \(temperature)") if temperature != oldValue { notifyTemperatureChange() } } } func notifyTemperatureChange() { print("Notifying temperature change...") } } let monitor = TemperatureMonitor() monitor.temperature = 25 monitor.temperature = 105
Use Cases for Property Observers:
-
Data Validation:
swiftclass Person { var age: Int { didSet { if age < 0 { age = 0 } if age > 150 { age = 150 } } } } -
UI Updates:
swiftclass ViewModel { var isLoading: Bool = false { didSet { updateLoadingIndicator() } } func updateLoadingIndicator() { // Update UI indicator } } -
Cache Invalidation:
swiftclass DataCache { var data: [String: Any] = [:] { didSet { invalidateCache() } } func invalidateCache() { // Clear cache } } -
Logging:
swiftclass Logger { var logLevel: LogLevel = .info { didSet { print("Log level changed from \(oldValue) to \(logLevel)") } } }
Important Notes:
- Property observers cannot be used with lazy properties
- Property observers cannot be used with constant properties (let)
- Setting property values in initializers does not trigger property observers
- Modifying property values in willSet does not trigger willSet again
- Modifying property values in didSet triggers property observers again
- If a property has a default value, property observers are not triggered during initialization
Best Practices:
- Use willSet for value validation and preparation
- Use didSet for side effects and updates
- Avoid performing time-consuming operations in property observers
- Be careful to avoid infinite loops (modifying property in didSet)
- Use meaningful parameter names to improve code readability