Swift・iOS

Swiftを中心に学んだことを記録に残すブログです。技術に関係ない記事もたまに書いています。

【SwiftUI】アプリを開いた時/閉じる時に処理を実行する(ライフサイクルがSwiftUI Appの場合)

 

はじめに

アプリを開いた時/閉じる時に処理を実行する方法に関してメモ。

 

開発環境

 

本題

実装に関して

ScenePhaseを使用することで表示状態を検知することができるため、Appのプロトコルに準拠した構造体でScenePhaseを利用することで、アプリを開いた時と閉じる時の処理を実装できる。

※参考:

 

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に実装することを検討した方がよいかもしれない。

 

おわりに

「気になった点」ですが、ドキュメントを調べ、文章を書き終わった時に、そもそもアプリを閉じる時にデータを保存して、アプリを開いた時にそのデータを読み込む仕様じゃないといけないケースがあまりないことに気づきました・・・前提がおかしいかもしれません・・・笑

アプリの利用時間の管理など一部を除けば、基本的にはデータに変更が発生した時に保存して、データが必要なタイミングで読み込めばいいじゃんと自分でつっこみつつ、調べた内容は残したいので削除しないでおきます笑

 

参考