YunDaeHyeon
← Lab

Application 실행 구조

스터디2025.06.25
  • UIKit
  • Swift

Application 실행 구조

이미지 출처 : https://developer.apple.com/documentation/uikit/about-the-app-launch-sequence

프로세스 시작 (엔트리 포인트)

  1. main() 이 실행되면서 Swift/Objective-C 런타임이 초기화
  • @UIApplicationMain(과거 방식) 혹은 @main(Swift 5.3+)이 엔트리 포인트를 직접 지정하여 내부적으로 UIApplicationMain을 호출
  1. UIApplicationMain이 UIApplication 객체와 AppDelegate 인스턴스를 생성하여 메인 런루프 시작

Scene 구성 (Info.plist와의 연계) iOS 13+

  • 시스템은 새로운 씬이 필요할 때 application(_:configurationForConnecting:options:) 를 호출한다.
  • 반환한 UISceneConfiguration 또는 Info.plist의 Scene Manifest를 활용해 씬을 만든다.
  • Info.plist에 UIApplicationSceneManifest 이나 UISceneConfigurations가 있으면 해당 구성을 우선적으로 참조한다.
  • AppDelegate 메서드를 구현하면 커스텀 로직으로 구성을 선택할 수 있다.

실행(런치) 유형

  • Cold Launch : 가장 무거운 유형으로, 프로세스가 없던 상태에서 처음 기동되는 실행 유형을 뜻한다.
  • Warm Launch : 백그라운드에서 중단 혹은 종료되지 않은 상태에서 다시 진입할 경우를 말한다. (상대적으로 가볍다.)
  • Background Launch : 푸쉬 처리, 백그라운드 작업 등으로 보이기 않게 기동되는 것을 말한다.

Cold Launch의 단계별 호출 순서 (UIKit + Scenes)

  1. 프로세스 시작 및 런타임 초기화
  • @main 엔트리 포인트로 UIApplicationMain에 진입
  • UIApplication 및 AppDelegate 인스턴스 생성
  1. AppDelegate 1회 세팅
  • application(_:didFinishLaunchingWithOptions:)이 실행되며 앱 전역 초기화를 진행한다.
  • 로깅, 분석, DI 컨테이너 빌드, 서드파티 SDK 등록, 기본 설정 등을 수행한다.
  • UI 생성은 하지 않는다.
  1. Scene 세션 구성
  • iOS 13 이상에서 application(_:configurationForConnecting:options:)을 호출시켜 새로 연결될 Scene의 UISceneConfiguration을 반환하여 클래스나 스토리보드를 지정한다.
  1. Scene 연결 (화면 준비)
  • SceneDelegate에서 scene(_:willConnectTo:options:)를 통해 UIWindow를 생성하거나 컴포지션 루트를 설정한다.
  • Window는 makeKeyAndVisible()을 활용!
  • 스토리보드를 사용하면 시스템이 직접 VC를 만든 뒤 해당 메서드에서 후처리한다.
  1. Foreground 전이 및 활성화
  • sceneWillEnterForeground(_:) 다음으로 sceneDidBecomeActive(_:)이 실행되며 앱이 최종적으로 Active 된다.

🤔 의존성 주입을 어디서 해야할까?

의존성 주입을 위한 Composition Root는 어디가 좋을 지 한 번 찾아보았다.

  • 앱 단위의 전역 단위라면?
  • AppDelegate의 application(_:didFinishLaunchingWithOptions:)가 좋다.
  • 여기서 로깅, 분석, 환경 설정 혹은 DI 컨테이너 생성 및 공유 객체를 등록하는 것도 좋을 것 같다.
  • UI나 화면 단위(씬 단위) 라면?
  • SceneDelegate의 scene(_:willConnectTo:options:)가 좋다고 한다.
  • UIWindow와 RootVC 생성 직전에 ViewModel이나 Usecase, 레포지터리 등을 주입할 수 있다.
  • SceneDelegate → RootVC → ChildVC로 이어지는 트리의 최상단에서 주입하면 하위로 깨끗하게 전파할 수 있기 때문이다!
  • 스토리보드를 사용한다면?
  • 똑같이 씬 델리게이트에서 scene(_:willConnectTo:options:)에서 스토리보드가 만든 RootVC를 캐스팅하여 의존성을 세팅하는 방법도 있다.

🤔 그렇다면 SceneDelegate에서 자식 VC까지 직접 접근해 주입해도 괜찮은가?

추후 테스트에 용이하거나.. 유지보수 측면으로 바라본다면 RootVC에서 의존성을 모아 주입하는 게 좋지 않을까싶다.

SceneDelegate에서 주입하게 되면 결합도가 올라가지 않을까?


💡 공식문서에서 언급되는 흔한 실수와 Best Practice

  1. UIWindow/RootVC를 AppDelegate에서 만들지 않기(iOS 13+)
  • 씬 기반에선 SceneDelegate가 UI 책임을 지는 구조가 좋다.
  1. 무거운 작업을 런치에 넣지 않기
  • didFinishLaunching에서 동기 네트워크/대용량 I/O 하지 않기.
  • 초기 화면이 늦어질 수 있다.
  1. 상태 복원/유지 전략
  • 첫 런치 시 한 번만 필요한 설정은 AppDelegate에서,
  • 사용자 UI 복원은 Scene 단위에서 진행하자!
  1. 멀티씬 고려 전략
  • iPad/외부 디스플레이, Stage Manager 등에서 씬이 여러 개 생길 수 있으므로 씬마다 독립 상태 관리를 해야한다!

핵심 정리

  • AppDelegate(앱단위)
  • 프로세스 기동 및 1회성 초기화
  • Scene 구성의 진입점
  • SceneDelegate(씬, 윈도우 단위)
  • UIWindow와 RootVC 설정
  • Active와 Background 전환 처리 담당
  • Application Lunch Flow 핵심
  1. 프로세스 부팅
  2. AppDelegate 초기화
  3. (iOS 13+) Scene 구성 및 연결 진행
  4. UIWindow와 RootVC 생성 및 연결
  5. 앱 Foreground 및 Active 처리
  • 실행 플로우 다이어그램 (생성은 GPT가 했습니다.)
[Process Start]
      |
      v
 UIApplicationMain  ---> AppDelegate 인스턴스 생성
      |
      v
 application(_:didFinishLaunchingWithOptions:)
 (전역 초기화/DI/로그 설정)
      |
      v
 application(_:configurationForConnecting:options:)
 (새 Scene 구성 반환)
      |
      v
 scene(_:willConnectTo:options:)
 (UIWindow 생성, RootVC 설정, makeKeyAndVisible)
      |
      v
 sceneWillEnterForeground  ->  sceneDidBecomeActive
 (보이기 직전)                 (사용자 입력 가능)

참고 자료

About the app launch sequence | Apple Developer Documentation

Responding to the launch of your app | Apple Developer Documentation

Managing your app’s life cycle | Apple Developer Documentation

application(_:didFinishLaunchingWithOptions:) | Apple Developer Documentation