[小ネタ] UISwitchのValueChangedイベントは値が変わってなくても発生する

2016.01.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは!加藤 潤です。 最近室内外の気温差のためか頭がボーっとすることが多いです。。インフルエンザも流行しているようですので体調管理には気を付けたいですね。

さて、今回はUISwitchの小ネタについて書きたいと思います。

開発環境

  • Xcode 7.2
  • iPhone 6s シミュレータ(iOS 9.2)

こんな画面がありました

まずは下記をご覧ください。

uiswitch_off

UITableViewCellの中にUISwitchが配置されているよく見るUIですね。 ここでUISwitchをONにすると、

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型のプロパティです。

クラッシュしました

上記の実装で問題ないように思いますが、以下のような操作をするとアプリがクラッシュしてしまいました。

uiswitch_crash

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イベントが意図せず発生するケースとその対応方法をお伝えしました。 実装は問題なさそうなのにクラッシュする場合はここを疑ってみると解決できるかもしれません。