SwiftUI AppDelegate VS init

Tabber·2022년 2월 4일
0

iOS Review

목록 보기
15/15
post-thumbnail

들어가기 전

오늘은 SwiftUI 상에서의 초기화를 구현해보겠다.
그리고 초기화는 Push Message를 사용하기 위해서 초기화를 진행하는 것으로 잡겠다.

원래 방법(UIKit)이라면 AppDelegate를 사용하여 초기화를 진행하는 방법으로 사용하면 됐지만, SwiftUI는 애초에 AppDelegate가 없다. (이건 뒤에서 더 자세히 알아보자) 그래서 초기화를 하는 (App Life Cycle) 방법이 몇가지가 존재하는데, 오늘은 그 방법에 대해서 알아보자.

일단 초기화하는 방법을
1. AppDelegate를 이용한 초기화
2. init() 을 이용한 초기화
로 나누어 설명해보고자 한다.

Using AppDelegate

이 방법은 사실 권장하는 방법은 아니다.
왜냐? 사실 AppDelegate의 역할(진입점)을 하는 것이 따로 존재하기 때문이다.

@main
struct PushMessageApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

위 코드에서 보이는 App 프로토콜 자체가 앱의 구성을 담당하는 구조체에 프로토콜을 지정해주어, 앱의 시작(Presenting) 지점을 정해주는 역할을 하게 된다.
또한 @main 을 통하여 앱이 시작되고 가장 먼저 들어가야하는 부분을 명시해주고 있기 때문에 AppDelegate가 필요하지가 않다.

그러나, 앱 초기화 부분 이외에도 AppDelegate 클래스에서 이루어지는 것들을 사용하고 싶을 때가 있을 것이다.

이땐 UIApplicationDelegate @UIApplicationDelegateAdaptor 를 이용하여 임시로 AppDelegate를 생성하여 사용하면 된다.

@main
struct PushMessageApp: App {

    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
    let gcmMessageIDKey = "gcm.message_id" // FCM 통신을 위해 필요한 key
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

@UIApplicationDelegateAdaptor 를 통해 UIKit과 동일하게 delegate를 사용할 수 있게 설정해준다. 이 부분이 있어야 delegate로 위임이 가능하다.

class AppDelegate: NSObject, UIApplicationDelegate {
 	func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    // 초기화 부분 (앱이 실행되고 처음 실행되는 메서드)
    }
    ...
}

AppDelegate를 선언할 때, NSObject, UIApplicationDelegate 두 프로토콜을 선언하여 AppDelegate의 역할을 할 수 있게 만들어준다.

그리고 난 뒤에 기존 UIKit 에서 사용하는 AppDelegate 처럼 사용하면 되는 것이다.

초기화 부분에 Push 관련 함수나 메서드등을 선언하면 되는 것이다.

푸시 관련 코드는 파이어베이스의 클라우드 메시징을 사용했기때문에 따로 코드를 게시하지는 않겠다.

Using init

이번에는 init() 을 사용하여 구현을 해보겠다.

SwiftUI 는 init() 사용할 수 있기 때문에, AppDelegate를 만들면서 까지 구현을 할 필요가 없다.

@main
struct PushMessageApp: App {

    let gcmMessageIDKey = "gcm.message_id"
    
    init() {
   		// PushService 싱글톤 인스턴스를 생성하여 관리
    	PushService.shared.initService()
    }
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

위 코드에서 사용한 Push관련 초기화는 싱글톤을 사용하여 init()에서 초기화 할 수 있게끔 설정한 방법이다.

이렇게 한다면, 사실 애플에서 원하는 방향으로 구현한 것이라고 생각한다.

애초에 AppDelegate를 사용하지 말라고 지웠는데, 다시 만든다는 것 자체가 모순이라고 생각하기 때문이다.

그런데 아직까지 SwiftUI가 완벽하게 개발이 되어 있는 것이 아니기에 AppDelegate 임의 생성과 같은 야매(?) 방법이 생겨난 것 같다.

+ SwiftUI 식 Life Cycle 정리

@main
struct PushMessageApp: App {
    @Environment(\.scenePhase) var scenePhase
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }.onChange(of: scenePhase) { newScenePhase in
            switch newScenePhase {
            case .active:
                print("active State")
            case .background:
                print("backgound State")
            case .inactive:
                print("Inactive State")
            default:
                print("Default State")
            }
        }
    }
}

iOS 14 버전부터 ScenePhase 라는 기능을 제공한다.

그리고 SwiftUI에서는 @Environment 속성 래퍼를 이용하여 값을 가져오게 된다.

그리고 onChange() 수정자를 사용하여 각 Life Cycle 상황일때의 작업을 정의하면 된다.

앱을 처음 실행시켰을 때

inactive : 아직 앱이 실행중이지만 동작은 불가능한 상태
backgound : 앱이 화면에 보이지 않는 상태

이렇게 정의하여 사용할 수가 있다.

정리

오늘은 SwiftUI 상에서의 App Life Cycle를 커스텀하는 방법에 대해 알아보았다.

AppDelegate를 이용하여 작동하는 방법과 init() 을 사용하여 작동하는 방법을 알아보았다.

마지막으로 SwiftUI 상에서의 Life Cycle를 정의하는 것 또한 알아보았다.

AppDelegate를 굳이 만들어서 정의하는 것 보다는 최대한 Apple이 원하는 방향, 간결하게 만드는 것이 중요하다는 것을 알게 되었다.

profile
iOS 정복중인 Tabber 입니다.

0개의 댓글