๐ŸŒ™

[Swift] ์•ฑ ์ฒซ ์‹คํ–‰ ์‹œ ํ•ด์•ผ ํ•  ์ดˆ๊ธฐํ™” ์ž‘์ ‘ ์ •๋ฆฌ(AppDelagate vs SceneDelegate)

yeggrrr๐Ÿผ 2025. 10. 5. 21:01
728x90





์˜ค๋Š˜์€ ๊ฐ€๋ฒผ์šด ์ฃผ์ œ๋กœ ๋ธ”๋กœ๊ทธ๋ฅผ ๋„์ ์—ฌ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
(์ถ”์„ ์—ฐํœด ๊ธฐ๋… ๐Ÿฅณ)



 

AppDelegate์—์„œ๋งŒ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋˜๋Š” ์ค„ ์•Œ์•˜๋Š”๋ฐ..
SceneDelegate์—์„œ๋„?

 

์•ฑ์ด ์‹คํ–‰๋  ๋•Œ, ์šฐ๋ฆฌ๋Š” ํ”ํžˆ AppDelegate์˜ didFinishLaunchingWithOptions์—์„œ ๋ชจ๋“  ์ดˆ๊ธฐํ™”๋ฅผ
์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.
ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ iOS 13 ์ดํ›„ ๋„์ž…๋œ SceneDelegate ๊ตฌ์กฐ์—์„œ๋Š” ์ด ์ƒ๊ฐ์ด ํ‹€๋ฆด ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์•ฑ์ด ์‹คํ–‰๋  ๋•Œ ๋ฐ˜๋“œ์‹œ ๊ฑฐ์ณ์•ผ ํ•˜๋Š” ์ดˆ๊ธฐํ™” ๋‹จ๊ณ„์™€
AppDelegate/SceneDelegate ๊ฐ๊ฐ์˜ ์—ญํ• ์„ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•œ๋‹ค.



๐Ÿ’๐Ÿป‍โ™€๏ธ ์—ญํ• ์˜ ์ฐจ์ด

  AppDelegate SceneDelegate
ํ˜ธ์ถœ ์‹œ์  ์•ฑ ํ”„๋กœ์„ธ์Šค ์‹œ์ž‘ ์‹œ ๊ฐ ์”ฌ ์ƒ์„ฑ ์‹œ
์—ญํ•  ์ „์—ญ์ ์ธ ์•ฑ ์ดˆ๊ธฐํ™”(SDK, Logger, DB ๋“ฑ) ํ™”๋ฉด(UI)์ดˆ๊ธฐํ™”, ์œˆ๋„์šฐ ์„ค์ •
์ƒ๋ช…์ฃผ๊ธฐ ์•ฑ ๋‹จ์œ„ UI ์„ธ์…˜ ๋‹จ์œ„
๋Œ€ํ‘œ ๋ฉ”์„œ๋“œ application(_:didFinishLaunchingWithOptions:) scene(_:willConnectTo:options:)

์ฆ‰, AppDelegate๋Š” ์•ฑ ์ „์ฒด์ ์ธ ํ™˜๊ฒฝ์„ ์ค€๋น„ํ•˜๊ณ , SceneDelegate๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์งˆ UI ์ง„์ž… ์ง€์ ์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ณณ์ด๋‹ค.

iOS 13์—์„œ UIScene(๋ฉ€ํ‹ฐ ์œˆ๋„์šฐ) ๊ฐœ๋…์ด ๋„์ž…๋˜๋ฉด์„œ, ํ•œ ์•ฑ์ด ์—ฌ๋Ÿฌ UI ์„ธ์…˜์„ ๋™์‹œ์— ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
๊ทธ๋ž˜์„œ ํ”„๋กœ์„ธ์Šค ๋‹จ์œ„ ์ด๋ฒคํŠธ(์•ฑ ์ „์—ญ ์ดˆ๊ธฐํ™”, SDK ๊ตฌ์„ฑ)๋Š” AppDelegate๊ฐ€ ๋งก๋„๋ก ์ฑ…์ž„์ด ๋ถ„๋ฆฌ๋˜์—ˆ๋‹ค.
๊ฒฐ๊ณผ์ ์œผ๋กœ '์•ฑ์˜ ์‹คํ–‰ ์‹œ์ (AppDelegate)'๊ณผ 'ํ™”๋ฉด์ด ๋ณด์ด๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ์‹œ์ (SceneDelegate)'์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ถ„๋ฆฌ๋˜์—ˆ๋‹ค.

๋ฉ€ํ‹ฐ ์”ฌ(iPad Split View, Stage Manager) ํ™˜๊ฒฝ์—์„œ 'ํ”„๋กœ์„ธ์Šค ๋‹จ์œ„(AppDelegate)'์™€ 'UI ์„ธ์…˜ ๋‹จ์œ„(SceneDelegate)' ์ด๋ฒคํŠธ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์กฐ์  ๋ณ€ํ™”์˜€๋‹ค.

 

๐Ÿ’๐Ÿป‍โ™€๏ธ ์•ฑ ์ฒซ ์‹คํ–‰ ์‹œ์ ์˜ ์ผ๋ฐ˜์ ์ธ ์ดˆ๊ธฐํ™” ์ˆœ์„œ

1. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋ฐ ์„ค์ •๊ฐ’ ๋กœ๋”ฉ
    - UserDefaultsManager๋ฅผ ํ†ตํ•ด ๊ธฐ๋ณธ ์„ค์ • ์„ธํŒ…
    - ์„œ๋ฒ„ ํ™˜๊ฒฝ, API Host, ์•ฑ ๋ฒ„์ „ ์ •๋ณด ๋กœ๋“œ
    - ์ฒซ ์‹คํ–‰ ์—ฌ๋ถ€(isFirstLaunch) ํ™•์ธ

2. ํ•„์ˆ˜ SDK ์ดˆ๊ธฐํ™”
    - ์˜ˆ: Firebase, Crashlytics, Analytics, Logger ๋“ฑ
    - ๋Œ€๋ถ€๋ถ„ AppDelegate์—์„œ ์ฒ˜๋ฆฌ

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    Logger.setup()
    return true
}


3. ๊ถŒํ•œ ํ™•์ธ ๋ฐ ๋น„๋™๊ธฐ ์š”์ฒญ
    - HealthKit, Notification, BLE, ์นด๋ฉ”๋ผ, ์›Œ์น˜ ๋“ฑ
    - UI๊ฐ€ ๋œจ๊ธฐ ์ „ ๋ฏธ๋ฆฌ ์ƒํƒœ๋ฅผ ํŒŒ์•…ํ•ด๋‘๋ฉด UX ์•ˆ์ •ํ™”์— ๋„์›€์ด ๋จ

HealthPermissionManager.shared.checkAuthorization()
// ๊ถŒํ•œ ํŒ์—…์€ ์‹ค์ œ ๊ธฐ๋Šฅ ์‚ฌ์šฉ ์‹œ์ ์— ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์ด HIG ๊ถŒ์žฅ์‚ฌํ•ญ์ž„
// (์ฆ‰, ์ตœ์ดˆ ์‹คํ–‰์—์„œ๋Š” ์ƒํƒœ ํ™•์ธ๋งŒ ํ•˜๊ณ , ์š”์ฒญ์€ ์‚ฌ์šฉ์ž ์•ก์…˜ ์งํ›„๋กœ ๋ฏธ๋ฃจ๋Š” ๊ฒƒ์ด ์ข‹์Œ)



4. SplashView ์ดˆ๊ธฐํ™”(SceneDelegate)
    - ์•ฑ์˜ ์ฒซ UI๋ฅผ ๋‹ด๋‹น(์ด์ „ ๊ธ€์—์„œ ๋‹ค๋ฃฌ ์Šคํ”Œ๋ž˜์‹œ ๋ทฐ)
    - ์บ์‹œ๋œ ์ด๋ฏธ์ง€ ํ‘œ์‹œ, ๋„ค๋น„๊ฒŒ์ด์…˜ ์ง„์ž… ๊ฒฐ์ • ๋“ฑ

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) {
    guard let windowScene = scene as? UIWindowScene else { return }
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = SplashViewController()
    window.makeKeyAndVisible()
    self.window = window
}

// Universal Link์˜ NSUserActivity(Handoff ํฌํ•จ)๋Š” ์—ฌ๊ธฐ๋กœ๋„ ์ „๋‹ฌ๋จ
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    DeepLinkManager.shared.handle(userActivity: userActivity)
}


5. ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ํ”„๋ฆฌํŽ˜์น˜
    - ์„œ๋ฒ„์—์„œ AppConfig, Notice, SplashImage ๋“ฑ์„ ๊ฐ€์ ธ์™€ ์บ์‹œ
    - ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ํ™”๋ฉด ํ‘œ์‹œ๋ฅผ ์ง€์—ฐ์‹œํ‚ค์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ

 

๐Ÿ’๐Ÿป‍โ™€๏ธ ๋น„๋™๊ธฐ ์ดˆ๊ธฐํ™” ์ˆœ์„œ ๊ด€๋ฆฌ

์•ฑ ์‹คํ–‰ ์‹œ ์—ฌ๋Ÿฌ ์ดˆ๊ธฐํ™” ๋กœ์ง์ด ๋™์‹œ์— ๋Œ์•„๊ฐ€๋ฉด ํƒ€์ด๋ฐ ์ถฉ๋Œ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.
(ex. ํŠนํžˆ Splash ํ™”๋ฉด์ด ๋จผ์ € ๋๋‚ฌ๋Š”๋ฐ SDK ์ดˆ๊ธฐํ™”๊ฐ€ ์•„์ง ์•ˆ๋๋‚œ ๊ฒฝ์šฐ)

์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด swift์˜ async let์„ ํ™œ์šฉํ•ด ๋ณ‘๋ ฌ ์‹คํ–‰ ํ›„ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.

final class AppInitializer {
    static let shared = AppInitializer()
    
    func runAll() async {
        async let loggerInit = Logger.setupAsync()
        async let firebaseInit = FirebaseManager.initializeAsync()
        async let healthPermission = HealthPermissionManager.shared.checkAuthorizationAsync()
        _ = await [loggerInit, firebaseInit, healthPermission]
    }
}

์œ„์™€ ๊ฐ™์ด ๊ตฌ์„ฑํ•˜๋ฉด ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ๋ณ‘๋ ฌ๋กœ ์ˆ˜ํ–‰ํ•˜๋ฉด์„œ๋„, ๋ชจ๋“  ์ž‘์—…์ด ๋๋‚˜๊ธฐ ์ „๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ’๐Ÿป‍โ™€๏ธ SceneDelegate → SplashViewController ํ๋ฆ„์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด?

App Launch
  ↓
AppDelegate.didFinishLaunching()      // SDK, Logger, Permission, ...
  ↓
SceneDelegate.willConnectTo()         // UIWindow, RootViewController ๊ตฌ์„ฑ
  ↓
SplashViewController.viewDidLoad()    // ์บ์‹œ ์ด๋ฏธ์ง€ ํ‘œ์‹œ
  ↓
SplashViewController.viewDidAppear()  // ์ผ์ • ์‹œ๊ฐ„ ํ›„ MainViewController ์ „ํ™˜

 

 

๐Ÿ’๐Ÿป‍โ™€๏ธ ๋”ฅ๋งํฌ(Deep Link) ์ฒ˜๋ฆฌ

- ๋”ฅ๋งํฌ: ์•ฑ ์™ธ๋ถ€์—์„œ ํŠน์ • ํ™”๋ฉด์œผ๋กœ ์ง„์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ
- iOS 13 ์ดํ›„๋ถ€ํ„ฐ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ SceneDelegate์—์„œ ์ฒ˜๋ฆฌ
- ๊ทธ ์ด์œ ๋Š” iOS๊ฐ€ UI ์„ธ์…˜(Scene) ๋‹จ์œ„๋กœ ๋”ฅ๋งํฌ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ๋•Œ๋ฌธ

ex. ์•ฑ์ด ์™„์ „ํžˆ ์ข…๋ฃŒ๋œ ์ƒํƒœ์—์„œ ๋งํฌ๋ฅผ ํ†ตํ•ด ์ง„์ž…ํ•˜๋Š” ๊ฒฝ์šฐ
→ AppDelegate์˜ scene(_:willConnectTo:)ํ˜ธ์ถœ ํ›„
→ SceneDelegate.scene(_:openURLContexts:)๊ฐ€ ์ด์–ด์„œ ํ˜ธ์ถœ๋จ

์ด์— ๋”ฐ๋ฅธ ์‹ค์ œ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋Š” SceneDelegate์—์„œ!

// SceneDelegate.swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else { return }
    DeepLinkManager.shared.handle(url: url)
}

์ฆ‰, ์ „์—ญ์ ์ธ URL ์Šคํ‚ด ๋“ฑ๋ก ๋ฐ Universal Link ์„ค์ •์€ AppDelegate, ์‹ค์ œ URL์„ ๋ถ„์„ํ•˜์—ฌ ํ™”๋ฉด ์ด๋™์„ ์ฒ˜๋ฆฌํ•˜๋Š”๊ฑด SceneDelegate์—์„œ ๋‹ด๋‹น!
๋งŒ์•ฝ ์•ฑ์ด ์ด๋ฏธ ์‹คํ–‰ ์ƒํƒœ๋ผ๋ฉด, SceneDelegate์—์„œ ์ง์ ‘ ๋ฃจํŠธ ๋ทฐ์ปจ์„ ์ฐพ์•„ ์ ์ ˆํ•œ ํ™”๋ฉด์œผ๋กœ ๋ผ์šฐํŒ… ์ง„ํ–‰

 




๊ฐœ๋ฐœ ๊ณต๋ถ€ ์ดˆ๊ธฐ์—๋Š” ๊ณผ๊ฑฐ์—๋Š” 'AppDelegate์˜€์œผ๋‚˜ iOS 13 ์ดํ›„ SceneDelegate๊ฐ€ ๋“ฑ์žฅํ•˜๋ฉฐ ๋Œ€์ฒด๋˜์—ˆ๋‹ค?' ์ •๋„๋กœ๋งŒ ์•Œ๊ณ  ์žˆ์—ˆ๋‹ค.
๋‹จ์ˆœํžˆ ์–ด๋””์„œ ๋“ค์€ ๋‚ด์šฉ์„ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„๋“ค์˜€์„ ๋ฟ, ์™œ ๊ทธ๋Ÿฐ ๊ตฌ์กฐ๊ฐ€ ์ƒ๊ธด ๊ฑด์ง€๋Š” ๊นŠ๊ฒŒ ์ƒ๊ฐํ•˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ ๊ฐ™๋‹ค.

์ด๋ฒˆ ๊ธ€์„ ์ •๋ฆฌํ•˜๋ฉด์„œ, AppDelegate์™€ SceneDelegate๊ฐ€ ๋‹จ์ˆœํžˆ ์—ญํ• ๋งŒ ๋‹ค๋ฅธ ๊ฒŒ ์•„๋‹ˆ๋ผ
์•ฑ์˜ ์‹คํ–‰ ์‹œ์ ๊ณผ UI ์ง„์ž… ์‹œ์ ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์กฐ์  ์žฅ์น˜๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ณผ๊ฑฐ ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด๊ณผ ๋”ฅ๋งํฌ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด์„œ '๊ทธ๋ƒฅ AppDelegate์— ๋„ฃ์œผ๋ฉด ๋˜๊ฒ ์ง€'๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋˜ ๋ถ€๋ถ„๋“ค์ด
์‹ค์ œ๋กœ๋Š” SceneDelegate ๋‹จ์—์„œ ์ฒ˜๋ฆฌ๋˜์–ด์•ผ ํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ช…ํ™•ํ•ด์กŒ๋‹ค :)

728x90

'๐ŸŒ™' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Swift] SplashView - ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด  (0) 2025.09.28
[Swift] KeychainManager  (0) 2025.09.21
[Swift] Keychain  (0) 2025.09.14