🍎

[iOS] アプリを開いた状態で端末をスリープ(ロック)にした場合のライフサイクル遷移

2023/11/11に公開

アプリを開いた状態から、閉じずにそのまま端末をスリープしロック画面に入った際のライフサイクル遷移をまとめる。
Always on (常時点灯)の有無、SwiftUIとUIKitで異なる遷移をする点に注意が必要。

結果

下記表では、アプリを開いた状態からスタートし、そのままスリープ(ロック画面)に入るまでのライフサイクル遷移を示す。

ScenePhase + WindowGroup.onChnage(of:)

常時点灯 有効 常時点灯 無効
(常時点灯機能がない端末含む)
inactive

active

inactive

background
inactive

background

ScenePhase + WindowGroup以外のViewでonChnage(of:)

常時点灯 有効 常時点灯 無効
(常時点灯機能がない端末含む)
inactive

active

background
background

UISceneDelegate(UIKitベース)、UIScene/UIAppilcationのnotifiction

常時点灯 有効 常時点灯 無効
(常時点灯機能がない端末含む)
deactive

active

deactive

background
deactive

background

常時点灯が有効な場合は、backgroundになる前に一度activeの状態が挟まる
その後、UISceneDelegate(UIKitベース)やUIScene/UIAppilcationのnotifictionでは、順当にdeactiveになってからbackgroundに行き着く。
また、ScenePhase(SwiftUIベース)では、WindowGroupに直接onChange(of: scenePhase)を付けると、同じく順当にinactiveになってからbackgroundに行き着く。
ただし、WindowGroupの子孫のViewでonChange(of:)を利用すると、inactive状態にはならずそのままbackgroundに行き着く。

常時点灯が無効な場合も、ScenePhase + WindowGroupと、UISceneDelegateや各種notificationは、順当にinactive(deactive)になってからbackgroundに行き着くが、ScenePhase + WindowGroup以外のViewはいきなりbackgroundになる

ScenePhaseしか監視していない場合、「backgroundになる直前は常にinactiveになる」と仮定した実装をしていると思わぬ挙動になり得る。

補足

UIKitベースのUIApplicationDelegateの実装クラス、SwiftUIベースのUIApplicationDelegateAdaptorDelegateTypeで指定するクラスのライフサイクル系のデリゲートメソッドは呼び出されなかった。
これは、ライフサイクル系のデリゲートメソッドがUISceneDelegate側に吸収された結果である。
https://developer.apple.com/documentation/uikit/app_and_environment/scenes/specifying_the_scenes_your_app_supports#3262270
(SwiftUIでは、内部的にSwiftUI.AppSceneDelegateというUISceneDelegateの実装クラスが存在する。)

調査方法

Discussion