LoginSignup
5
4

More than 5 years have passed since last update.

UISwitchのsetOn()でAction接続したメソッドが呼ばれないようにする

Last updated at Posted at 2018-10-30

動作環境

xcode9.4.1
Swift4.1.2

やりたかったこと

UISwitchをAction接続し、値が変わったときに呼ばれるメソッドvalueChanged(_sender: UISwitch)を作りました。
そのメソッド内で、特定の処理を行い、処理が完了しなかった場合はUISwitchの値を元に戻す動きを実装したいと考えました。
今回の処理は時間がかかるものであったため、valueChange(_sender: UISwitch)が呼ばれた直後にUISwitchの値を戻し、処理が完了した場合に再度、UISwitchの値を変更するように実装しました。

setOn()メソッドについて

UISwitchの値の変更には、setOn()メソッドを用いました。
このメソッドは、Appleのドキュメントによると、
Setting the switch to either position does not result in an action message being sent.
つまり、setOn()メソッドが呼ばれ、UISwitchの値が変わっても、valueChanged(_sender: UISwitch)は呼ばれないということのようです。

一旦実装してみたが…

switchChange.swift
@IBAction func valueChange(_ sender: UISwitch) {
        let isOn = switch.isOn
        switch.setOn(!isOn, animated: false)

        /* 時間のかかる後続の処理 */
}

簡略化しているが、上記の様に、valueChange(_sender: UISwitch)が呼ばれた直後に、setOn()を用い、UISwitchの値を反転させています。

しかし、このsetOn()が呼ばれた直後、再びvalueChange(_sender: UISwitch)が呼ばれ、二重に処理が行われてしまいました。

原因と対策

setOn()からはアクションメッセージが送られないから、valueChange(_sender: UISwitch)は呼ばれないはず…と思い、調査をしました。
すると、どうやらこのsetOn()はメインスレッドで呼ばれなかった場合には、アクションメッセージが送られてしまうようでした。
そこで、以下のようにコードを変更しました。

switchChange.swift
@IBAction func valueChange(_ sender: UISwitch) {
        let isOn = switch.isOn
        DispatchQueue.main.async {
            self.switch.setOn(!isOn, animated: false)
        }

        /* 時間のかかる後続の処理 */
}

実行してみると、setOn()が行われても、valueChange(_sender: UISwitch)は呼ばれず、想定通りの動作を行うことができました。

参考文献

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4