iOS7
UISwitch
Event ValueChanged
Bug
Continuous Calling

iOS7 UISwitch its Event ValueChanged Calling continuously is this Bug or what..?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If UISwitch seems to fire valueChanged continuously while the user drags it, that is usually not a framework bug. The event is designed to fire when the control’s value changes, and during interactive dragging the switch can cross the on-off threshold more than once. The real question is not whether the event is “wrong,” but whether your handler is doing too much work for a control that can emit multiple changes during tracking.

What valueChanged Means for UISwitch

UISwitch is a UIControl. For controls in UIKit, valueChanged means the control’s value changed during interaction. That does not guarantee “only once after the finger lifts.”

So if the user drags the thumb and the control toggles state back and forth across its threshold, the target-action method can run multiple times.

This is often noticeable when the handler:

  • starts a network request
  • writes to disk
  • triggers an expensive animation
  • posts duplicate analytics events

The event itself is fine; the handler design is usually the problem.

Keep valueChanged for Immediate UI Feedback

If you want the interface to react instantly, valueChanged is still the right event.

swift
1import UIKit
2
3final class ViewController: UIViewController {
4    let wifiSwitch = UISwitch()
5    let statusLabel = UILabel()
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        wifiSwitch.addTarget(self, action: #selector(switchChanged(_:)), for: .valueChanged)
10    }
11
12    @objc private func switchChanged(_ sender: UISwitch) {
13        statusLabel.text = sender.isOn ? "Enabled" : "Disabled"
14    }
15}

This is cheap work, so repeated calls are harmless.

Delay Expensive Side Effects

If changing the switch triggers real work, separate the UI update from the expensive action. A debounce is a practical pattern.

swift
1import UIKit
2
3final class ViewController: UIViewController {
4    let syncSwitch = UISwitch()
5    private var pendingWork: DispatchWorkItem?
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        syncSwitch.addTarget(self, action: #selector(switchChanged(_:)), for: .valueChanged)
10    }
11
12    @objc private func switchChanged(_ sender: UISwitch) {
13        pendingWork?.cancel()
14
15        let finalState = sender.isOn
16        let work = DispatchWorkItem {
17            print("Commit switch state:", finalState)
18        }
19
20        pendingWork = work
21        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: work)
22    }
23}

Now the control can emit live changes while the expensive action runs only after interaction settles.

If You Need "Interaction Finished"

Sometimes you do not care about intermediate values at all. In that case, listen for the touch-ending control events and read the final isOn state there.

swift
1syncSwitch.addTarget(self, action: #selector(commitSwitchState(_:)), for: [.touchUpInside, .touchUpOutside, .touchCancel])
2
3@objc private func commitSwitchState(_ sender: UISwitch) {
4    print("Final state:", sender.isOn)
5}

This can work well when the app only needs the final committed value. Keep in mind that valueChanged and touch-ending events solve different problems, so choose the one that matches the interaction you want.

Why It Felt Like a Bug in iOS 7

Older UIKit behavior changes often stood out because many handlers assumed “one gesture equals one callback.” With a switch, that assumption is brittle. As soon as the framework emits value transitions during dragging rather than only after release, repeated side effects become visible.

That is why many reports describe the issue as a bug when the deeper problem is that the action method was written as if it were a one-shot commit event.

Common Pitfalls

  • Treating valueChanged as if it guarantees exactly one callback per interaction.
  • Putting network calls or heavy persistence directly in the event handler.
  • Emitting analytics or business events on every intermediate switch state.
  • Using only touch-ending events when the UI also needs live feedback.
  • Debugging UIKit first when the real issue is non-idempotent side effects in the handler.

Summary

  • Repeated valueChanged callbacks during dragging are usually expected behavior, not a UISwitch bug.
  • Use valueChanged for cheap immediate UI updates.
  • Debounce or delay expensive side effects if repeated callbacks are a problem.
  • If you only need the final state, handle touch-ending events and read isOn once.
  • Design the handler around interaction semantics instead of assuming the framework will call it only once.

Course illustration
Course illustration

All Rights Reserved.