[小ネタ] UISwitchのValueChangedイベントは値が変わってなくても発生する
はじめに
こんにちは!加藤 潤です。 最近室内外の気温差のためか頭がボーっとすることが多いです。。インフルエンザも流行しているようですので体調管理には気を付けたいですね。
さて、今回はUISwitchの小ネタについて書きたいと思います。
開発環境
- Xcode 7.2
- iPhone 6s シミュレータ(iOS 9.2)
こんな画面がありました
まずは下記をご覧ください。
UITableViewCellの中にUISwitchが配置されているよく見るUIですね。 ここでUISwitchをONにすると、
こんな感じで1つセクションが追加されます。もちろんOFFにしたら追加されたセクションは削除されます。
UISwitchのValueChangedイベントで実行するメソッドは具体的には下記のようになっていました。
func switchValueChanged(aSwitch: UISwitch) { self.switchOn = aSwitch.on self.tableView.beginUpdates() if self.switchOn { // スイッチがONならセクションをInsert self.tableView.insertSections(NSIndexSet(index: 1), withRowAnimation: .Fade) } else { // スイッチがOFFならセクションをdelete self.tableView.deleteSections(NSIndexSet(index: 1), withRowAnimation: .Fade) } self.tableView.endUpdates() }
self.switchOn
は現在のUISwitchのON/OFFを保持するBool型のプロパティです。
クラッシュしました
上記の実装で問題ないように思いますが、以下のような操作をするとアプリがクラッシュしてしまいました。
Xcodeのデバッグコンソールを見てみると以下のログが出ていました。
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete section 1, but there are only 1 sections before the update'
どうやら削除するセクションと実際のセクション数が合ってないようです。
しかしこのログが出るということはセクションを削除しようとしたということです。
ということは、switchValueChanged
メソッドが呼ばれているということになります。
実際にswitchValueChanged
メソッドの先頭でログを出力するようにしたところ、上記の操作を行うと何回もメソッドが呼ばれることが確認できました。
対応方法
意図せずValueChangedイベントのメソッドが呼ばれてしまうことがわかりました。 実はこの時、UISwitchのON/OFFの状態が変わってなくてもメソッドが呼ばれます。(ValueChangedなのに...)
ということで対応は簡単です。 以下のようにUISwitchのON/OFFに変更がなければ何もしなければいいのです。
func switchValueChanged(aSwitch: UISwitch) { guard self.switchOn != aSwitch.on else { // ON/OFFに変更がなければ処理をしない return } self.switchOn = aSwitch.on self.tableView.beginUpdates() if self.switchOn { // スイッチがONならセクションをInsert self.tableView.insertSections(NSIndexSet(index: 1), withRowAnimation: .Fade) } else { // スイッチがOFFならセクションをdelete self.tableView.deleteSections(NSIndexSet(index: 1), withRowAnimation: .Fade) } self.tableView.endUpdates() }
まとめ
今回はUISwitchのValueChangedイベントが意図せず発生するケースとその対応方法をお伝えしました。 実装は問題なさそうなのにクラッシュする場合はここを疑ってみると解決できるかもしれません。