[iOS] アプリを開いた状態で端末をスリープ(ロック)にした場合のライフサイクル遷移
アプリを開いた状態から、閉じずにそのまま端末をスリープしロック画面に入った際のライフサイクル遷移をまとめる。
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ベースのUIApplicationDelegateAdaptorのDelegateTypeで指定するクラスのライフサイクル系のデリゲートメソッドは呼び出されなかった。
これは、ライフサイクル系のデリゲートメソッドがUISceneDelegate側に吸収された結果である。
(SwiftUIでは、内部的にSwiftUI.AppSceneDelegateというUISceneDelegateの実装クラスが存在する。)
調査方法
- iPhone 15 Pro (iOS 17.1.1), iPhone 14 Pro (iOS 17.1.1), iPhone 13 Pro (iOS 16.7.2), iOS Simulatorで検証
- SwiftUIベースとUIKitベースのアプリ両方でライフサイクル系の各種状態やメソッド、通知を監視
- SwiftUIベース:
-
ScenePhase+onChange(of:) -
UIApplicationDelegateAdaptor-
UIApplicationDelegateを実装したクラスで下記デリゲートメソッドの呼び出しを監視
-
-
- UIKitベース:
-
UISceneDelegateを実装したクラスで下記デリゲートメソッドの呼び出しを監視 -
UIApplicationDelegateを実装したクラスで下記デリゲートメソッドの呼び出しを監視- SwiftUIベースに同じ
-
- 共通:
-
UISceneのnotificationを購読 -
UIApplicationのnotificationを購読
-
- SwiftUIベース:
Discussion