モチベーション
ライフサイクルメソッドの説明は、解説付きでケースを列挙されることが多いですが、いまいちイメージがしにくいと感じることが多く感じます。特に、ActiveとInactiveのタイミングは分かりにくいことが多いのではないでしょうか。
この記事では、Sceneベースの各種ライフサイクルメソッドにprintを貼って、active/inactiveとはどのようなステートなのかを視覚的に把握します。(※タイミングの列挙はしません。1つ2つ取り上げるだけです)
解説
1. アプリの起動
ライフサイクル
シーンベースのライフサイクルでも、共通系は呼ばれます。なのでdidFinishLauching
がまず始めに呼ばれます。
次に、SceneDelegate
のwillConnect
が呼ばれます。このメソッドは、システム・ユーザー起点にかかわらず、新しいシーンがアプリケーションに接続される直前に呼ばれます。そしてその後は順当にwillEnterForeground
, didBecomeActive
と呼ばれていきます。
didFinishLaunching
willConnect
willEnterForeground
didBecomeActive
2. SplitViewの割合変化
もっとも分かりやすい状態遷移です。視覚的な状態と実際の状態が一致しており、直感的に理解できます。
中間状態
ライフサイクル
中間状態では、システムによるSplitViewの操作中で、アプリケーション自体の操作はできないため、画面は前面に出ていますがInactive
な状態です。
didFinishLaunching
willConnect
willEnterForeground
didBecomeActive
willResignActive
完了
ライフサイクル
割合がユーザーによって決められ、操作が終了するとdidBecomeActive
が呼ばれていることが分かります。
注目すべきは、どちらの状態でもforeground
であることは変わらず、active/inactive
だけの変化であるということです。
didFinishLaunching
willConnect
willEnterForeground
didBecomeActive
willResignActive
didBecomeActive
3. SplitViewから閉じる
ライフサイクルメソッド
先程の中間状態からの復帰ではdidBecomeActive
になりましたが、こちらはそのまま閉じてしまった(右側の比率を100%にした)ので、didEnterBackground
が呼ばれました。
didFinishLaunching
willConnect
willEnterForeground
didBecomeActive
willResignActive
didBecomeActive
willResignActive
didEnterBackground
まとめ
「ForegroundなのにInactiveな状態ってどのようなものなのだろう?」という疑問に対して、これまで「システム的にはそういう状態が存在する」と受け入れて理解していた人も、上記のSplitViewの例を見れば「前面に出ているのに、アプリケーションにアクセスできない瞬間が存在する」というのを視覚的に把握できたかと思います。
他には、アプリ一覧を開いた時にInactive
になったりしますが、詳細は別の方の記事をご参照ください。
実装
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print("didFinishLauching")
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
print("configurationForConnecting")
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
print("willConnect")
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
print("didDisconnect")
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
print("didBecomeActive")
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
print("wiiResignActive")
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
print("willEnterForeground")
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
// Save changes in the application's managed object context when the application transitions to the background.
(UIApplication.shared.delegate as? AppDelegate)?.saveContext()
print("didEnterBackground")
}
}