#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 를 사용할 필요가 없지 않을까요?
오늘 포스팅은 여기서 마무리하겠습니다 감사합니다