SwiftUI 생명주기 이벤트 핸들링의 모든 것

공태현·2022년 5월 5일
0

SwiftUI

목록 보기
1/1
post-thumbnail

안녕하세요 iOS dev 루크입니다 😇

오늘은 SwiftUI 앱의 생명주기에 대해서 알아보려고 합니다.

iOS 14 업데이트와 함께 App 프로토콜이 AppDelegate 를 대체하게 되었습니다.

그에 따라서 생명주기의 활용법 또한 변경이 되었는데요

SwiftUI 프로젝트를 하게된다면 당연히 바뀐 생명주기도 다룰 줄 알아야겠죠 ㅎ

하나씩 살펴 보겠습니다.

@main
struct MyApp: App //- App protocol 을 채택하는 struct 의 이름은 자유로우나 일반적으로 ~~App 이라고 짓는다.
{
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

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()
        }
    }
}
  • 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")
            }
        }
    }
}

화면 기록 2022-04-03 오후 6.27.06.mov

scenePhase 🌟

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

active

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

inactive

앱 스위칭 ing

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

background

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


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

@UIApplicationDelegateAdaptor 프로퍼티 사용

SwiftUI 에서도 그래도 AppDelegate 를 사용해야 하는 순간이 온다. 바로 UIkit 에 머물러있는 Swift 패키지들을 사용할 때(특히 FireBase🔥) 인데,,, (작성일 기준입니다)

@main 
struct MyApp: App { 
		init() { 
				FirebaseApp.configure() // 🚨 불가능 
		} 
		var body: some Scene { 
				WindowGroup { 
						ContentView() 
				} 
		} 
}

이는 생각보다 간단히 해결이 가능합니다

//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()
        }
    }
}
  1. AppDelegate 클래스 선언
    1. NSObject 프로토콜 준수
    2. UIApplicationDelegate 프로토콜 준수 → Delegation 함수 사용가능
  2. @UIApplicationDelegateAdaptor 프로퍼티 래퍼 사용 AppDelegate 클래스 타입 전달

이렇게 해서 아직 App protocol 에서 사용이 불가능한 기능들을 사용할 수 있답니다.

Ex. remote push notification

중요한 점은 AppDelegate 를 어떤용도로든 사용할 수 있게 되지만,

이는 어디까지나 App 구조체 내부에서 사용이 불가능한 기능에만 사용하는 것이 현명하겠네요 ㅎ

@main
struct MyApp: App
{
    init() {
        //앱 초기 설정 작업
    }

    var body: some Scene 
}

이렇게 깔끔한데 굳이 AppDelegate 를 사용할 필요가 없지 않을까요? 😃

오늘 포스팅은 여기서 마무리하겠습니다 감사합니다 😊

profile
"안녕하세요👋 춤을 사랑하는 댄서이자, iOS dev. 공태현(Luke)입니다. 😎"

0개의 댓글