RxSwift初心者です。完全自分用の学習備忘録として残します。
開発中、RxSwiftで以下の実装方法に詰まりました。
- ユーザーが誤ってデータをDBへ保存せずに、アプリをキルしようとする
- アプリがバックグラウンドに移行した際にローカルにデータを保存
- アプリがキルされ、再度、アプリを起動する
- ローカルに保存されたデータの有無を確認
- データがある場合、「前回保存されていないデータがあります。データを保存しますか?」という文言で
UIAlert
を表示 - 保存ボタンを押下し、データを保存する非同期処理を実行
- 非同期処理中、仮にエラーが発生するとする
- 画面上に「エラー データの保存に失敗しました。保存しますか?」というエラー
UIAlert
を表示 -
6, 7, 8
を繰り返す
この記事では、1 〜 2
を扱い、3 〜 9
は別の記事**「[RxSwift]詰み② UIAlertを活用してデータ保存の失敗時に繰り返しリトライさせたい」**で扱います。
1. ユーザーが誤ってデータをDBへ保存せずに、アプリをキルしようとする
うっかりデータを保存し忘れてアプリを終了させてしまうユーザーもいると思います。開発者は対策を考える必要があります。
2. アプリがバックグラウンドに移行した際にローカルにデータを保存
結論から言うと、Realm
を使用してローカルにデータを保存させています。
特定のViewControllerに以下の処理を実装して、アプリがバックグラウンドに移行したことを検知し、その時点でのユーザーの勉強時間等をRealm
に保存するようにしています。
// バックグラウンド移行時
NotificationCenter.default.addObserver(
self,
selector: #selector(self.didEnterBackground),
name: UIApplication.didEnterBackgroundNotification,
object: nil
)
// バックグラウンドへの移行時の処理
@objc func didEnterBackground() {
// アプリをキル(完全終了)した場合でもローカルに勉強記録等を保存しておく
viewModel.saveStudyProgress(shouldSaveLocallyOnKill: true)
}
- 少し苦戦した話
はじめは、Realm
ではなく、直接Firebase
に保存する処理を実装していましたが、以下のフローを行うとFirestore
へデータが正常に更新されない時がありました。
-
アプリをフォアグラウンド状態にする(普通にアプリの画面を表示させている状態)
-
app switcher
にアプリ画面を表示する(以下のような状態です)
(この時点ではまだ@objc func didEnterBackground()
は呼ばれません。) -
2の状態からアプリをキル(アプリ画面を上にスワイプさせて完全終了させた状態)させる
-
ここで初めて
@objc func didEnterBackground()
に処理が入り、Firestore
へのデータ保存処理を実行 -
Firebase console
でFirestore
を確認するも、データが正常に更新されない
・ とあるフィールドは正常に更新されていて、とあるフィールドが更新されなかったり…
・ 時には、全てのデータが正常に更新されていたり… 逆も然り…
アプリがキルされる”直前”に@objc func didEnterBackground()
が呼ばれている → すなわち、言い換えれば、app switcher
からであれば、キルされないと@objc func didEnterBackground()
が呼ばれないということか…
そして、データが正常に更新されない理由は、おそらく非同期処理中にアプリがキル(完全に終了)されたためだと思います。
app switcher
に移行した時点で@objc func didEnterBackground()
が呼ばれると思っていたのですが、違ったようです。勉強になりました。
以上の問題から、Realm
を使用して、一旦ローカルにデータを保存しておくと言う方針にしました。