はじめに
これまでのあらすじ
- 同一のiCloudアカウントにログインした2つの端末で、CoreDataの変更を通知することができた。
- アプリのアイコンに通知数のバッジをつけることができた。
今回のお題
アプリのアイコンに表示されている通知数のバッジがリセットされない。
通知が発生するたびにどんどんカウントアップされてしまう。

これを解決していきます。
まずは現状確認
バッジを表示させているコード
AppDelegate.swift
内のfunc application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
に書かれた以下のコードです。
let info = CKSubscription.NotificationInfo()
info.shouldBadge = true
shouldBadgeというのはそもそも何?
改めてApple公式ドキュメントを見ておきましょう。

デフォルトではfalse
が設定されているとのこと。
true
にすると、通知の度にバッジに表示されている現在のカウントに加算していくとあります。
通知の度にバッジに表示されている現在のカウントに加算 とな。shouldBadge
をtrue
にしている限り、加算され続けるのではないか。
では課題に対処していきましょう
まずは仮説を立ててみました
- 通知数を現在のバッジの値の負値として、通知を出す
shouldBadge
をfalse
に変えてみる(リセットされれば幸い)- なんとかしてリセットする処理を見つける
- そもそも通知のときに処理するのではなく、アプリ本体側でなんとかする
順番に試してみます。
順番に試すと言ったな。あれは嘘だ。
正解は4つ目でした。
それにしても3つ目のは一体何でしょうね?自分で書いておきながら、わけがわからないよ。
少し脱線してしまいました。
UIApplication.shared.applicationIconBadgeNumber = 0
でOKです。
実行するタイミングですが、アプリアイコンをタップして起動した時点で消せば良いと思います。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
内ですね。
ただし、今回作ってみたサンプルアプリは、Fetchボタンを押さないと通知された情報は表示されません。起動しただけでは通知された情報の中身を知らないわけです。
つまりFetchボタンを押さずにアプリを閉じたときは通知数を残しておいてほしいということです。今回に限れば、冒頭のリセット処理はFetchボタンを押したタイミングで実行するのが最適かと思います。
消えるかな?
消えることは消えました。

新たな課題
それでも良い感じになりません。試行錯誤は続きます。なかなか一筋縄にはいかないです。
どれだけやっても終わらない夏休みの課題のようです。
値自体がリセットされていない
バッジ数はゼロになりましたが、次の通知が来たときにリセット前の値に加算されたものが復活してしまいました。
いじっているうちに恐ろしい値になりました。通知の履歴でも残っているのか?
今もいじる度に増え続けています。

通知が飛んだり飛ばなかったり
デバッグ中端末から通知を飛ばそうとしたときに、エラーが出ました。The request was cancelled because it conflicted with another active import operation.
なるほどコンフリクト(´・ω・`)
これは同期非同期関連かな?
余談
リセット処理の実行タイミング
起動時にリセットするパターンがよく採られると思います。ただし、今回のような事例や特定の通知分だけ値をリセットしてほしいなど、いろいろなパターンがあると思います。
そのあたりは臨機応変の対応が必要ですね。
まぁ、今回のもFetchボタンを押したタイミングが本当にいいタイミングかどうかはわからないわけですが。これは、実際に利用してみて違和感が無いか等の検討が要ります。