【Swift5】フォアグラウンドに復帰したら画面を表示する

作成したアプリにロック機能を実装した後、アプリがバックグラウンドからフォアグラウンドに復帰した時にもロック画面を表示したいなーと思い、調べてました。
復帰したら applicationDidBecomeActive(_:) でUI更新しましょうって書かれていることが多いのですが、新しく画面を出すと何も表示されないので ( ͡° ʖ̯ ͡°) ってなりました。
そんな人に向けた記事ですー。

前提条件

・Xcode12.2
・Swift5(Unused SwiftUI)

ダメだったコード

最初にコード載っけます。

これはダメでした。
うんともすんとも言いません ( ˙-˙ )
NotificationCenter を使っているのが原因ではなく、applicationDidBecomeActive(_:) でも同じです。

コンソールには whose view is not in the window hierarchy 的なエラーが出ましたー
iOSエンジニアは一度は遭遇したことあるエラーだと思いますが、ご存知の通り「画面ねーのにどうやって遷移すんの?w」って笑われてます。

applicationDidBecomeActive(_:) のドキュメントを見ると、

If your app was previously in the background, you can also use it to refresh your app’s user interface.
After calling this method, UIKit posts a didBecomeActiveNotification to give interested objects a chance to respond to the transition.

アプリが以前にバックグラウンドにあった場合は、それを使用してアプリの UI を更新することもできます。
このメソッドを呼び出して didBecomeActiveNotification を投げて、関心のあるオブジェクトに遷移に応答する機会を与えます。

的なことを言われてますが、だからやってんじゃんよ!って悪態つきたくなります。

動くコード

さきほどの画面がないってのは、遷移先の画面ではなく、遷移元(表示中)の画面のことです。
僕がこのエラーに遭遇したアプリの構成は、大元の ViewController に ContainerView があり、そこに UITabBarController と ViewController があり…とちょっと複雑な作りなんです。

最前面の ViewController を取得するコードを実装することも考えたのですが、それよりも UIWindow を新たに作ってどこからでも安全に呼び出せる方がいいなと思ったので、その方向で実装します。

どこからでも新規 UIWindow で呼び出せるクラスを作る

遷移先の dismiss を検知する

遷移先の dismiss を遷移元に検知させるために、UIAdaptivePresentationControllerDelegate を使用します。
遷移先の dissmiss に以下のコードを追加します。

これで検知することができます。

実際に呼び出す

アプリがバックグラウンドからフォアグラウンドに復帰した時にもロック画面を表示するためにやっていたので、最初のダメだったコードを修正します。

これで安全にロック画面が表示されます。
遷移元とは完全に独立していて didAppear らへんも無関係なので、安全に使えます ヽ(ヅ)ノ

さいごに

SwiftUI だとまた違う方法になりますが、出来ることがもっと増えてから取り組みたいと思います。

コメント