AppDelegate에서 주로 하는 일
- 앱 런치 시 의존성 초기화 (`didFinishLaunchingWithOptions`)
- 푸시 토큰 등록/갱신, 원격 알림 처리 진입
- 앱 전체 공통 설정(로그, 분석, SDK 초기화)
핵심은 범위(scope)다. AppDelegate는 "앱 전체 레벨" 이벤트를 담당하고, SceneDelegate는 "각 화면 세션(window scene) 레벨" 생명주기를 담당한다.
기록 없음
| 구분 | AppDelegate | SceneDelegate |
|---|---|---|
| 관리 범위 | 앱 프로세스 전체 | 각 `UIWindowScene`(창/세션) 단위 |
| 대표 책임 | 푸시 등록, 앱 시작 초기화, 글로벌 서비스 설정 | window 생성/연결, 화면 전환 진입점 구성, scene 상태 반응 |
| 멀티윈도우 대응 | 전체 정책 관리 | scene마다 독립 상태 관리 |
iPad 멀티윈도우(여러 scene) 환경에서 한 앱이 여러 화면 세션을 동시에 가질 수 있기 때문이다. 앱 전체 이벤트와 개별 화면 세션 이벤트를 분리해야 책임이 명확해진다.
// AppDelegate: 앱 전체 레벨
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// 글로벌 초기화
return true
}
// SceneDelegate: scene(창) 레벨
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = scene as? UIWindowScene else { return }
let window = UIWindow(windowScene: windowScene)
window.rootViewController = RootViewController()
self.window = window
window.makeKeyAndVisible()
}| 입력 이벤트 | 수신 위치 | 처리 원칙 |
|---|---|---|
| 로그인 상태 변경 | AppDelegate 또는 전역 Auth 서비스 | 전역 상태만 갱신하고, 화면 전환은 활성 scene 라우터에 위임 |
| 딥링크 | SceneDelegate (`openURLContexts`, `continue userActivity`) | scene 단위 라우팅 큐에 적재 후 현재 화면 상태에서 안전하게 소비 |
| 푸시 탭 진입 | AppDelegate 수신 후 scene 식별/선택 | 즉시 화면 전환하지 말고 대상 scene 결정 후 라우팅 이벤트 전달 |
// 1) AppDelegate: 이벤트를 전역으로 수집
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any]) async
-> UIBackgroundFetchResult {
AppEventBus.shared.publish(.push(userInfo))
return .noData
}
// 2) SceneDelegate: 활성 scene에서만 라우팅 실행
func sceneDidBecomeActive(_ scene: UIScene) {
Task { @MainActor in
for await event in AppEventBus.shared.events {
guard let windowScene = scene as? UIWindowScene else { continue }
SceneRouter(windowScene: windowScene).handle(event)
}
}
}UIApplication (앱 당 1개, 싱글턴)
│
├── connectedScenes: Set<UIScene>
├── openSessions: Set<UISceneSession>
│
└── UISceneSession ←──1:1──→ UIWindowScene
↑
│ windowScene (strong 참조)
│
UIWindow ── rootViewController
UIWindow (keyboard)
UIWindow (alert)| 객체 | 개수 | 역할 |
|---|---|---|
| UIApplication | 앱당 1개 | 앱 전체 대표, 이벤트 분배, Scene들 관리 |
| UISceneSession | Scene당 1개 | Scene의 메타데이터/설정, 상태 복원 정보 |
| UIScene | Session당 1개 | 추상 클래스 (직접 사용 X) |
| UIWindowScene | Scene당 1개 | UIScene 서브클래스, 화면 특성(orientation, traits) 제공 |
| UIWindow | Scene당 N개 | ViewController 컨테이너, 이벤트 전달 시작점 |
// UIWindow가 UIWindowScene을 참조 (strong)
class UIWindow {
var windowScene: UIWindowScene? // Window → Scene
}
// UIWindowScene은 연결된 Window들을 조회 (weak 추정)
class UIWindowScene {
var windows: [UIWindow] { get } // Scene → Windows (역방향 조회)
}
// 관계: 1:N
// - Window 1개는 Scene 1개만 참조
// - Scene 1개에 Window 여러 개 연결 가능 (main, keyboard, alert 등)class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// 1️⃣ Scene 연결 (최초 생성)
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, ...) {
guard let windowScene = scene as? UIWindowScene else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = MainViewController()
window?.makeKeyAndVisible()
}
// 2️⃣ Scene 연결 해제
func sceneDidDisconnect(_ scene: UIScene) { }
// 3️⃣ Active (사용자 상호작용 가능)
func sceneDidBecomeActive(_ scene: UIScene) { }
// 4️⃣ Inactive (상호작용 불가, 아직 보임)
func sceneWillResignActive(_ scene: UIScene) { }
// 5️⃣ Foreground 진입 예정
func sceneWillEnterForeground(_ scene: UIScene) { }
// 6️⃣ Background 진입
func sceneDidEnterBackground(_ scene: UIScene) { }
}class SceneDelegate: UIWindowSceneDelegate {
var window: UIWindow? // SceneDelegate가 Window 소유
var coordinator: AppCoordinator?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, ...) {
guard let windowScene = scene as? UIWindowScene else { return }
let window = UIWindow(windowScene: windowScene)
self.window = window
// Coordinator에게 화면 구성 위임
coordinator = AppCoordinator(window: window)
coordinator?.start() // rootVC 설정 + 화면 흐름 관리
}
}
class AppCoordinator {
private let window: UIWindow // 참조만 (소유 X)
func start() {
window.rootViewController = UINavigationController(rootViewController: HomeVC())
window.makeKeyAndVisible()
}
}