We often use onChange () modifier in SwiftUI to react to environment or state changes, but it can be used with any properties that have Equatable
value, even a computed property.
If we need to perform an action when either of multiple properties changes, then it’s simpler to make a computed property, rather than add multiple onChange()
modifiers for each of them.
Let’s say we have a view to set an alarm with a DatePicker
and an activation Toggle
. When user activates the toggle we set an alarm for selected date. When user changes the date, we cancel the previous alarm if it has not been canceled yet and set a new one. When user deactivates the toggle, we cancel the alarm.
In our case we depend on changes in the DatePicker
and the Toggle
. We could set up two onChange()
modifiers to react to changes in each of them. But we could also define an intermediary computed property that will only return a date if alarm is activated and otherwise return nil
. Then we can react to changes in that computed date.
struct AlarmView: View
@State private var date = Date()
@State private var isOn = false
var alarmDate: Date?
isOn ? date : nil
var body: some View
VStack
DatePicker(
"Alarm Time", selection: $date,
displayedComponents: [.hourAndMinute]
)
Toggle("Activate", isOn: $isOn)
.onChange(of: alarmDate) [alarmDate] newDate in
if alarmDate != nil
AlartScheduler.cancelAlarm()
if let date = newDate
AlartScheduler.setNewAlarm(for: date)
struct AlartScheduler
static func cancelAlarm()
print("Cancelling old alarm...")
static func setNewAlarm(for date: Date)
print("Setting alarm for: (date)")
Note that we are capturing the old value of alarmDate
in onChange
closure, so that we only cancel the alarm if the old value isn’t nil
. If the old value is nil
it means that the alarm was already canceled.
For updates about the blog and development tips follow us on Twitter @nilcoalescing.