오늘은 SwiftUI 상에서의 초기화를 구현해보겠다.
그리고 초기화는 Push Message를 사용하기 위해서 초기화를 진행하는 것으로 잡겠다.
원래 방법(UIKit)이라면 AppDelegate를 사용하여 초기화를 진행하는 방법으로 사용하면 됐지만, SwiftUI는 애초에 AppDelegate가 없다. (이건 뒤에서 더 자세히 알아보자) 그래서 초기화를 하는 (App Life Cycle) 방법이 몇가지가 존재하는데, 오늘은 그 방법에 대해서 알아보자.
일단 초기화하는 방법을
1. AppDelegate를 이용한 초기화
2. init() 을 이용한 초기화
로 나누어 설명해보고자 한다.
이 방법은 사실 권장하는 방법은 아니다.
왜냐? 사실 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 관련 함수나 메서드등을 선언하면 되는 것이다.
푸시 관련 코드는 파이어베이스의 클라우드 메시징을 사용했기때문에 따로 코드를 게시하지는 않겠다.
이번에는 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 임의 생성과 같은 야매(?) 방법이 생겨난 것 같다.
@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이 원하는 방향, 간결하게 만드는 것이 중요하다는 것을 알게 되었다.