In previous versions of iOS, IBActions were only triggered in response to user action. Now, it seems that they are also triggered by interactions through code on the same thread as the user interaction... I probably didn't word it that well, but here is an example:
@IBAction func switchToggled(_ sender: UISwitch) {
sender.setOn(!sender.isOn, animated: true)
}
Neato. There's our element. The behavior that I would expect in iOS 9 and below is:
- User taps switch
- Animation begins
- IBAction is hit, and animation reverses
However, in iOS 10, step 3 is revised to
- IBAction is hit,
setOn
is called within action, then IBAction is hit again
For UISwitch
, the IBAction only seems to get called twice.
My guess is that since the second setOn
matches the direction of the current animation, it doesn't trigger another valueChanged
event for the switch, therefore not triggering a 3rd IBAction.
Another observation is that if the setOn
method is called in a completion block or something, it does not trigger the IBAction. For example:
someViewController.present(someOtherController,
animated: true,
completion: { theSwitch.setOn(true) })
This does not trigger an IBAction, regardless of the animation state of the UISwitch
Was there a change in iOS 10 that I was not privy to? Or is my assumption that IBActions are exclusively meant for explicit user interactions incorrect? (Yes, I know you can manually send events to UI elements to make them do things, but this isn't what I'm talking about)
Cheers!