applicationDidEnterBackground
バーコードをスキャンするアプリを作りたくて、カップラーメンのバーコードをスキャンすると、銘柄に応じて調理の時間(待ち時間)を計測できるアプリを作成しています。
どんなアプリも作るとハマりどころはあるもの。
今回のツボをいくつか備忘のため記載します。
1. バックグラウンド、フォアグラウンドの検出
2. バックグラウンド中のタイマーの値とフォアグランドに復帰した時の残り時間の値
1. バックグラウンド、フォアグラウンドの検出
AppDelegate.m にはアプリがバックグラウンドになったタイミング、バックグラウンドからフォアグラウンドになったタイミング、それぞれ呼ばれるメソッドがあります。
// アプリがバックグラウンドに回ったとき呼ばれる
- (void)applicationDidEnterBackground:(UIApplication *)application
// あぷりがフォアグラウンドになったときに呼ばれる
- (void)applicationWillEnterForeground:(UIApplication *)application
何か処理をしたいときはこれらのメソッドに書けばよいことになります。
この考えで進めたところ、残りの待ち時間はアプリのプロパティにしておらず、他のクラスの property にしていたので appDelegate.m から待ち時間 property にアクセスできず困りました。
しょうがないので、appDelegate では notification を設定し、notification が呼ばれたらそれを他のクラスで検出し、検出したクラスからローカル通知を設定するようにしました。
オブジェクト指向の場合(というか、アプリとして制作する時には)、オブジェクト間の値のやりとりで少し遠回りすることが多いなと・・・
appDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSNotification* myNotification = [NSNotification notificationWithName:@"applicationDidEnterBackground" object:self];
// 通知を行う
[[NSNotificationCenter defaultCenter] postNotification:myNotification];
}
viewController.m
- (void)applicationDidEnterBackground
{
// 通着があるとこっちが呼ばれる。ローカル通知を設定。省略
}
ベストソリューションなのか気がかりです。
バックグラウンドに復帰した際も、同様にしました。
2. バックグラウンド中のタイマーの値とフォアグランドに復帰した時の残り時間の値
アプリがバックグラウンドに移行すると、アプリは idle 状態になってしまい、アプリの時間が止まります。
ラーメンタイマーの場合、3 分経っても検出できなくなってしまうので、それを回避するため notification を経由してローカル通知する方法を実装しました。
一方、ユーザの利用方法を考えてみると、
1. ラーメンタイマーセット
2. Safari でネットブラウズ
3. 3 分後ローカル通知で時間が来たことに気付く
という流れに沿うと問題ないのですが、アプリの利用者は気まぐれなもので、自身の行動を振り返ってみても、
1. ラーメンタイマーセット
2. Safari でネットブラウズ
3. ラーメンタイマー確認、あと 1 分ね
2 に戻る(以降何度か繰り返す・・・)
ということも考えられます。
この場合、3 のときに表示する残りの待ち時間は、2 で消費した時間を減じて欲しいところなんですが、アプリがバックグラウンドになると、idle になるのでアプリの時間も止まってしまいそのままでは減算されません・・・
つまり、上記の例では、Safari でネットブラウズしていた時間分だけ余計に待たないとならないことになります。
換言すると、「3 分待ちたければアプリを常にフォアグランドにしておけ」という、意図せず俺様仕様のアプリに・・・
そもそも、バックグラウンドに回ると idle になってしまうこの仕様ってどうなんだ? マルチタスクだろ? と思わなくもないですが、スマートフォンなのでバッテリーの消費を抑えるためのものだったりするのかなと勝手に想像しました(パソコンとは違うのですね)。
回避方法ですが、
・バックグラウンドになったら、その時点の日時を記録する
・フォアグラウンドになったら、その時点の日時から、先ほどの日時を減じて秒を算出
・待ち時間から秒数を減じて表示
以上のような流れでうまくいきました。
ふうぅ。