-
UIApplicationDelegateAdaptorSwiftUI 2023. 8. 28. 11:19
안녕하세요. 그린입니다 🍏
이번 포스팅에서는 UIApplicationDelegateAdaptor에 대해 학습해보겠습니다 🙋🏻
UIApplicationDelegateAdaptor?
우선 UIApplicationDelegateaAdaptor는 SwiftUI에서 UIKit app delegate를 생성하는데 사용하는 프로퍼티 래퍼입니다.
@MainActor @propertyWrapper struct UIApplicationDelegateAdaptor<DelegateType> where DelegateType : NSObject, DelegateType : UIApplicationDelegate
선언은 위와 같이 되어 있는 프로퍼티 래퍼이죠!
SwiftUI의 라이프 사이클을 사용하는 앱에서 앱딜리게이트 콜백을 처리하려면 UIApplicationDelegate 프로토콜을 준수하여야하고, 각자 필요한 딜리게이트 메서드를 구현해야 합니다.
예시로 원격 노티피케이션을 등록하는 메서드를 사용해야된다고 가정해볼께요!
그럼 가장 먼저 아래와 같이 UIApplicationDelegate를 채택하는 앱딜리게이트 코드를 작성하게 됩니다.
class MyAppDelegate: NSObject, UIApplicationDelegate, ObservableObject { func application( _ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data ) { // Record the device token. } }
그 후 이제 SwiftUI App 코드에서 UIApplicationDelegateAdaptor 프로퍼티 래퍼를 사용해 SwiftUI에게 딜리게이트 타입에 대해 선언해줍니다.
@main struct MyApp: App { @UIApplicationDelegateAdaptor private var appDelegate: MyAppDelegate var body: some Scene { ... } }
혹은 선언을 이렇게도 쓸 수 있어요!
@UIApplicationDelegateAdaptor(MyAppDelegate.self) var appDelegate
SwiftUI는 딜리게이트를 인스턴스화하고 생명주기 이벤트가 발생할때마다 응답해 딜리게이트 메서드를 호출합니다.
딜리게이트 어댑터는 앱 선언부에서만 정의하고, 앱에서 꼭 한번만 선언해야 합니다!
만약 여러번 선언을 하게 된다면 SwiftUI는 런타임 에러를 발생시키죠.
앱의 딜리게이트가 위 코드 예시처럼 ObservableObject 프로토콜을 준수하는 경우에, SwiftUI는 생성한 딜리게이트를 Environment에 저장합니다.
즉, 앱 내 어떤 Scene 혹은 View에서도 EnvironmentObject 프로퍼티 래퍼를 통해 해당 딜리게이트에 접근할 수 있습니다.
@EnvironmentObject private var appDelegate: MyAppDelegate
이렇게 하면, 딜리게이트에서 선언한 Published 프로퍼티에 대한 바인딩을 얻기 위해 $(달러) 기호 접두사를 사용할 수 있습니다.
해당 부분에서 궁금하시다면 projectedValue를 학습해보면 됩니다 😃
중요한건 가급적이면 가능한 경우 앱 딜리게이트 없이 앱의 생명주기 이벤트를 관리하는것이 좋습니다.
예를들어, application(_:didFinishLaunchingWithOptions:)와 같은 딜리게이트 콜백에 의존하기 보다는 ScenePhase의 변화를 처리하는것을 SwiftUI에서는 우선적으로 고려해야 합니다.
Scene Delegate
일부 iOS 앱은 앱 단축키와 같은 Scene 기반 이벤트를 처리하기 위해 UIWindowSceneDelegate를 정의합니다.
class MySceneDelegate: NSObject, UIWindowSceneDelegate, ObservableObject { func windowScene( _ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem ) async -> Bool { // Do something with the shortcut... return true } }
앱 딜리게이트 내부의 application(_:configurationForConnecting:options:) 메서드에서 scene delegate의 타입을 반환함으로 이러한 종류의 딜리게이트를 SwiftUI 앱에 제공할 수 있습니다.
extension MyAppDelegate { func application( _ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions ) -> UISceneConfiguration { let configuration = UISceneConfiguration( name: nil, sessionRole: connectingSceneSession.role) if connectingSceneSession.role == .windowApplication { configuration.delegateClass = MySceneDelegate.self } return configuration } }
UISceneConfiguration 인스턴스를 설정할 때, Scene 클래스나 스토리보드 대신 딜리게이트 클래스만 명시하면 됩니다.
SwiftUI는 딜리게이트 인스턴스를 생성하고 관리하며, 관련된 딜리게이트 콜백을 전송하죠.
앱 딜리게이트와 마찬가지로, Scene delegate를 ObservableObject로 만들 경우, SwiftUI는 자동으로 이를Envrionment에 저장합니다.
그렇게 되면 EnvironmentObject 프로퍼티 래퍼를 통해 해당 딜리게이트에 접근하고 Published 속성들에 대한 바인딩을 생성할 수 있습니다.
마무리
물론, App/SceneDelegate를 UIKit처럼 만들고 구성하고 거기서 ContentView를 올려서 App 코드 없이도 사용할 수 있죠.
SceneDelegate에서 UIWindowScene 타입의 scene을 만들고 window로 해당 뷰를 띄워주는 진입점을 사용하는 그런 사용법처럼 말이죠!
그것도 하나의 방법이며, App 구조체를 통해 조금 더 SwiftUI스럽게 가져가는것에서 오늘 학습해본 UIApplicationDelegateAdaptor가 도움이 될것 같습니다 🚀
참고 레퍼런스
https://developer.apple.com/documentation/swiftui/uiapplicationdelegateadaptor
'SwiftUI' 카테고리의 다른 글
DatePicker & Picker 사용하기 (43) 2023.09.11 SwiftUI의 onChange 사용 시 주의할 부분 (45) 2023.09.05 SwiftUI에서 타이머 구현하기 (feat. User Notification) (50) 2023.08.22 SwiftUI에서 Notification 사용하기 (40) 2023.08.17 SwiftUI로 음성메모 구현하기 (38) 2023.08.15