はじめに
アプリを開いた時/閉じる時に処理を実行する方法に関してメモ。
開発環境
- macOS Big Sur 11.2.3
- Xcode 12.4
- Swift 5.3.2
本題
実装に関して
ScenePhaseを使用することで表示状態を検知することができるため、Appのプロトコルに準拠した構造体でScenePhaseを利用することで、アプリを開いた時と閉じる時の処理を実装できる。
※参考:
- https://developer.apple.com/documentation/swiftui/scenephase
- How to detect when your app moves to the background or foreground with scenePhase - a free SwiftUI by Example tutorial
SampleApp.swift
import SwiftUI @main struct SampleApp: App { @Environment(\.scenePhase) private var scenePhase var body: some Scene { WindowGroup { ContentView() } .onChange(of: scenePhase) { phase in switch phase { case .active: print("The scene is in the foreground and interactive.") case .inactive: print("The scene is in the foreground but should pause its work.") case .background: print("The scene isn’t currently visible in the UI.") @unknown default: break } } } }
気になった点
仮に、アプリを閉じる時にデータをUserDefaultsで保存し、アプリを開いた時に読み込みたい場合。ScenePhaseのactiveとbackgroundを使って処理を実装することができるし、実際に試したところ期待した動作になっていた。
しかし、Appleのドキュメントを読むと、backgroundはリソースを開放する用途で使用するような印象で、データを保存する処理を実行するのに最適なのか気になった。
※参考:https://developer.apple.com/documentation/swiftui/scenephase/background
そこで、プロジェクトのライフサイクルがUIKit App Delegateの場合はどうなのかAppleのドキュメントを確認したところ、データの保存に関しては"sceneWillResignActive(_:)"または、"applicationWillResignActive(_:)"で実行し、データの読み込みに関しては、"sceneWillEnterForeground(_:)"または"applicationWillEnterForeground(_:)"で実行するのがよさそうであることがわかった。
※参考:
そのため、もしScenePhaseで期待した動作にならない場合は、UIApplicationDelegateAdaptorを使ってAppDelegateに処理を実装するか、SwiftUI Appのライフサイクルを諦めてSceneDelegateに実装することを検討した方がよいかもしれない。
おわりに
「気になった点」ですが、ドキュメントを調べ、文章を書き終わった時に、そもそもアプリを閉じる時にデータを保存して、アプリを開いた時にそのデータを読み込む仕様じゃないといけないケースがあまりないことに気づきました・・・前提がおかしいかもしれません・・・笑
アプリの利用時間の管理など一部を除けば、基本的にはデータに変更が発生した時に保存して、データが必要なタイミングで読み込めばいいじゃんと自分でつっこみつつ、調べた内容は残したいので削除しないでおきます笑
参考
-
https://developer.apple.com/documentation/swiftui/scenephase
-
https://developer.apple.com/documentation/swiftui/scenephase/active
-
https://developer.apple.com/documentation/swiftui/scenephase/inactive