Search
♻️

SwiftUI App Lifecycle 의 모든 것

#SwiftUI #생명주기 #루크 #Luke #iOS #background
안녕하세요 iOS dev 루크입니다
오늘은 SwiftUI 앱의 생명주기에 대해서 알아보려고 합니다.
iOS 14 업데이트와 함께 App 프로토콜이 AppDelegate 를 대체하게 되었습니다.
그에 따라서 생명주기의 활용법 또한 변경이 되었는데요
SwiftUI 프로젝트를 하게된다면 당연히 바뀐 생명주기도 다룰 줄 알아야겠죠 ㅎ
하나씩 살펴 보겠습니다.
@main struct MyApp: App //- App protocol 을 채택하는 struct 의 이름은 자유로우나 일반적으로 ~~App 이라고 짓는다. { var body: some Scene { WindowGroup { ContentView() } } }
Swift
복사

1. @main

앱의 시작점인 Entry Points 를 지정하는 역할을 합니다.
기존 AppDelegate 에서 진행되었던 리소스 초기화는 SwiftUI 에 들어와서는 init() 을 사용하게 됩니다
@main struct MyApp: App { // 앱이 실행됨과 동시에 첫 view 생성전 미리 구성해야하는 즉 loading 과정 구현 let persistenceController = PersistenceController.preview init() { //앱 실행 전 초기화 작업 or 필요한 네트워킹 //앱이 실행되기도 전에 실행해야하는 서비스는 이렇게 구현 //앱을 실행하기위해 구성해야 하는 항목들은 init() 에 구현 } var body: some Scene { WindowGroup { ContentView() } } }
Swift
복사
body 프로퍼티에는 WindowGroup 객체가 자리잡고 있다. 이 객체는 cross-platform struct 로 여러개의 윈도우를 가진 scene 을 나타낸다. macOS iOS 등등에서 사용할 수 있으며, 앱내의 view 들의 계층구조를 담아내는 container 라고 생각하면된다.
WindowGroup 내에는 앱의 첫번째 view 를 선언해준다. 위 코드에서는 BookList() 가 앱 실행시 처음으로 띄워질 view 가 된다.

AppDelegate 대체 사항

AppDelegate에서 사용하던
applicationDidBecomeActive 백그라운드 → 포그라운드 이동 후
applicationWillResignActive 포그라운드 → 백그라운드 이동 전
applicationDidEnterBackground 포그라운드 → 백그라운드 이동 후
들이 다른 방식으로 대체되었습니다

2. SwiftUI lifecycle 이벤트에 반응하기

@Environment 프로퍼티 래퍼를 사용해 현재 앱의 생명주기 상태를 가져올 수 있습니다.
이렇게 가져온 값에 대해 .onChange(of:) 메서드를 사용해서 해당 생명주기의 대응할 수 있게 됩니다
import SwiftUI @main struct MyApp: App { @Environment(\.scenePhase) var scenePhase var body: some Scene { WindowGroup { ContentView() } .onChange(of: scenePhase) { newScenePhase in switch newScenePhase { case .active: print("App is active") case .inactive: print("App is inactive") case .background: print("App is in background") @unknown default: print("unexpected Value") } } } }
Swift
복사

scenePhase

ScenePhase enum 은 3개의 상태를 나타냅니다.

active

앱이 포그라운로 올라왔을 때

inactive

앱 스위칭 ing
디바이스 화면 전경에 앱이 존재하지만 일시정지 상태이며, 이벤트도 받을 수 없는 상태를 의미

background

아이폰 홈 화면으로 나왔을 때

3. UIKit 패키지 사용을 위해 AppDelegate 가 필요할 때

@UIApplicationDelegateAdaptor 프로퍼티 사용

SwiftUI 에서도 그래도 AppDelegate 를 사용해야 하는 순간이 온다. 바로 UIkit 에 머물러있는 Swift 패키지들을 사용할 때(특히 FireBase) 인데,,, (2022 5월 12 일 기준 아래코드 정상 작동함을 확인했습니다)
@main struct MyApp: App { init() { FirebaseApp.configure() // 🚨 불가능 } var body: some Scene { WindowGroup { ContentView() } } }
Swift
복사
이는 생각보다 간단히 해결이 가능합니다
//MyApp.Swift import SwiftUI class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { //패키지 초기화 작업 수행 FirebaseApp.configure() //👍🏻 return true } } @main struct MyApp: App { //아래 프로퍼티 래퍼를 활용 @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { ContentView() } } }
Swift
복사
1.
AppDelegate 클래스 선언
a.
NSObject 프로토콜 준수
b.
UIApplicationDelegate 프로토콜 준수 → Delegation 함수 사용가능
2.
@UIApplicationDelegateAdaptor 프로퍼티 래퍼 사용 AppDelegate 클래스 타입 전달
이렇게 해서 아직 App protocol 에서 사용이 불가능한 기능들을 사용할 수 있답니다.
Ex. remote push notification
중요한 점은 AppDelegate 를 어떤용도로든 사용할 수 있게 되지만,
이는 어디까지나 App 구조체 내부에서 사용이 불가능한 기능에만 사용하는 것이 현명하겠네요 ㅎ
@main struct MyApp: App { init() { //앱 초기 설정 작업 } var body: some Scene }
Swift
복사
이렇게 깔끔한데 굳이 AppDelegate 를 사용할 필요가 없지 않을까요?
오늘 포스팅은 여기서 마무리하겠습니다 감사합니다