- July 30, 2025
- Mins Read
Swift lets you observe and respond to changes in a property’s value by attaching willSet
and didSet
observers to any stored property (except lazy and let
constants).
class TemperatureSensor {
var temperature: Double = 0.0 {
willSet {
print("About to change from \(temperature)° to \(newValue)°")
}
didSet {
let delta = temperature - oldValue
print("Changed by \(delta)°")
if temperature > 100 {
print("Warning: Overheat!")
}
}
}
}
let sensor = TemperatureSensor()
sensor.temperature = 75.0
// About to change from 0.0° to 75.0°
// Changed by 75.0°
sensor.temperature = 120.0
// About to change from 75.0° to 120.0°
// Changed by 45.0°
// Warning: Overheat!
willSet
vs. didSet
willSet
didSet
class Counter {
var count: Int = 0 {
willSet {
print("Counter will change from \(count) to \(newValue)")
}
didSet {
print("Counter did change from \(oldValue) to \(count)")
}
}
}
// Test:
let counter = Counter()
counter.count = 1
// Expect:
// Counter will change from 0 to 1
// Counter did change from 0 to 1
counter.count = 5
// Expect:
// Counter will change from 1 to 5
// Counter did change from 1 to 5
Swift structs and classes get a default memberwise initializer (for structs) or a simple default initializer (for classes without stored-property defaults), but you can—and often should—define your own initializers to enforce invariants or provide convenient defaults.
struct User {
let username: String
var age: Int
var isPremium: Bool
// Custom initializer
init(username: String, age: Int = 18, isPremium: Bool = false) {
self.username = username
// can validate or adjust values if needed
self.age = max(age, 0) // no negative ages
self.isPremium = isPremium
}
}
// Usage:
let guest = User(username: "GuestUser")
// guest.age == 18, guest.isPremium == false
let vip = User(username: "Star", age: 30, isPremium: true)
init()
only if all stored properties have default values.self
in a Method or Initializerinit(name: String) {
self.name = name
}
self
makes it explicit you’re referring to the instance, especially inside closures or nested scopes.struct Rectangle {
var width: Double
var height: Double
// Custom initializer enforcing positive dimensions
init(width: Double, height: Double) {
self.width = max(width, 0)
self.height = max(height, 0)
}
}
// Test:
let r1 = Rectangle(width: 5, height: 3)
assert(r1.width == 5 && r1.height == 3)
let r2 = Rectangle(width: -2, height: 4)
assert(r2.width == 0 && r2.height == 4)
print("Initializer tests passed")
class Circle {
var radius: Double
init(radius: Double) {
self.radius = radius // use of self to disambiguate
}
func scale(by factor: Double) {
self.radius *= factor // self makes it clear we're modifying the property
}
func description() -> String {
// self is optional here, but allowed
return "Circle with radius \(self.radius)"
}
}
// Test:
let circle = Circle(radius: 2)
circle.scale(by: 3)
assert(circle.radius == 6)
print(circle.description()) // "Circle with radius 6.0"
PermissionsSwiftUI displays and handles permissions in SwiftUI. It is largely inspired by SPPermissions. The UI is highly customizable and resembles an Apple style. ...
Introduction PagerTabStripView is the first pager view built in pure SwiftUI. It provides a component to create interactive pager views ...
1. Creating Your Own Structs In Swift, a struct is a value type that you define with the struct keyword. ...