우리가 iOS 앱 시작 시간을 60% 줄인 방법

발행: (2026년 2월 4일 오후 03:04 GMT+9)
7 min read
원문: Dev.to

Source: Dev.to

죄송합니다만, 번역하려는 전체 텍스트를 제공해 주시면 해당 내용을 한국어로 번역해 드릴 수 있습니다. 현재는 링크만 제공되어 있어 실제 기사 본문을 확인할 수 없습니다. 번역이 필요한 텍스트를 복사해서 알려주시면 바로 도와드리겠습니다.

소개

앱 실행 시간은 첫인상입니다. 앱이 열리는 데 2–3 초 이상 걸리면 사용자가 눈치채고, 5 초가 되면 떠납니다. 우리는 중급 기기에서 콜드 런치 시간이 4.8–5.2 초에 머물렀던 실제 iOS 앱에서 이 문제를 겪었습니다. 집중적인 최적화 스프린트 후 실행 시간을 ≈ 60 % 줄여 ~2 초 수준으로 감소시켰습니다.

1단계 — 최적화하기 전에 측정하기

추측하지 말고 측정하세요. 우리는 다음을 사용했습니다:

  • Xcode Instruments → Time Profiler
  • App Launch Metric (Xcode Organizer)
  • DYLD_PRINT_STATISTICS
  • Custom logging for application(_:didFinishLaunchingWithOptions:)

기준 수치

지표
Cold launch5.1 s
Warm launch2.7 s
Main thread blocked3.4 s

통찰 – 대부분의 시간이 첫 프레임이 렌더링되기 전에 소요되었으며, 이는 시작 작업이 메인 스레드를 차단하고 있음을 의미합니다.

Step 2 — Find What Blocks the Main Thread

Problems we discovered:

  • 런치 시 무거운 의존성 주입
  • 시작 중 데이터베이스 마이그레이션
  • 동기식 네트워크 호출
  • 큰 스토리보드 초기화
  • 너무 많은 동적 프레임워크

첫 화면이 나타나기 전에 모두 발생합니다.

60 % 향상을 가져온 최적화

1. 비핵심 작업 지연 처리 (가장 큰 효과)

Before

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    setupAnalytics()
    migrateDatabase()
    preloadImages()
    fetchRemoteConfig()
    return true
}

After

DispatchQueue.global(qos: .background).async {
    self.setupAnalytics()
    self.migrateDatabase()
    self.preloadImages()
    self.fetchRemoteConfig()
}

// Or, even later:
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    // non‑critical work
}

Result – 즉시 약 1.8 초 절감.

2. 의존성 지연 로드

Before

let networkManager = NetworkManager()
let cacheManager   = CacheManager()
let analytics      = Analytics()

After

lazy var networkManager = NetworkManager()

Result – 약 400 ms 절감 (해당 기능이 사용될 때만 비용 발생).

3. 스토리보드 복잡도 감소

초기 스토리보드에는 20개 이상의 뷰 컨트롤러, 무거운 Auto Layout, 커스텀 폰트, 내장 네비게이션이 포함돼 있었습니다.

Fixes

  • 스토리보드를 더 작은 조각으로 나눔.
  • 가벼운 런치 스크린 사용.
  • 무거운 뷰를 코드 기반 UI로 이동.

Result – 약 300–500 ms 절감.

4. 동적 프레임워크 최적화

각 동적 프레임워크는 런치 오버헤드(dyld 링크, 심볼 해석)를 추가합니다. 우리는 18개의 프레임워크를 사용하고 있었습니다.

Actions

  • 작은 프레임워크를 병합.
  • 일부를 정적 라이브러리로 전환.
  • 사용되지 않는 pod 제거.

Result – 약 700 ms 절감.

5. 데이터베이스 마이그레이션을 시작 시점에서 분리

우리는 매 실행마다 SQLite 마이그레이션을 수행하고 있었습니다.

Fix

  • 스키마 버전이 변경된 경우에만 마이그레이션 실행.
  • 첫 화면이 표시된 뒤 백그라운드 큐에서 마이그레이션 수행.

Result – 약 600 ms 절감.

6. 이미지 및 에셋 최적화

Problems

  • 큰 PNG와 불필요한 @3x 에셋.
  • 런치 시점에 이미지 미리 로드.

Fixes

  • 에셋을 WebP/HEIF 형식으로 변환.
  • 필요할 때 이미지 로드.
  • 미리 로드 제거.

Result – 약 200–300 ms 절감.

최종 지표

지표
콜드 런치5.1 s2.0 s
웜 런치2.7 s1.1 s
메인 스레드 차단3.4 s0.9 s

총 개선: ≈ 60 % 더 빠른 실행.

주요 교훈

해야 할 일

  • 비핵심적인 모든 것을 연기하세요.
  • 의존성을 지연 로드하세요.
  • Instruments로 측정하세요.
  • 동적 프레임워크를 최소화하세요.
  • 런치 스크린을 가볍게 유지하세요.

하지 말아야 할 일

  • 시작 시 API를 호출하지 마세요.
  • 메인 스레드에서 데이터베이스를 마이그레이션하지 마세요.
  • 모든 서비스를 즉시 초기화하지 마세요.
  • 무거운 스토리보드를 로드하지 마세요.
  • 메인 스레드를 차단하지 마세요.

빠른 시작 최적화 체크리스트

  • 가벼운 런치 스크린을 사용하세요.
  • 서비스를 지연 로드하세요.
  • 불필요한 프레임워크를 제거하세요.
  • 분석 초기화를 연기하세요.
  • 데이터베이스 작업을 백그라운드에서 수행하세요.
  • 시작 시 무거운 DI 컨테이너 사용을 피하세요.
  • Instruments를 사용해 정기적으로 프로파일링하세요.

최종 생각

런치 시간은 직접적으로 영향을 미칩니다:

  • 유지율
  • 평점
  • 인지된 품질
  • 전환율

사용자는 몇 초 만에—문자 그대로—앱을 판단합니다. 시작 성능을 사후 생각이 아니라 기능으로 다루세요. 작업을 현명하게 연기하고, 지연 로딩을 적용하며, 불필요한 요소를 제거함으로써 핵심 기능을 변경하지 않고도 60 % 개선을 달성했습니다.

Back to Blog

관련 글

더 보기 »

[SUI] 검색 바

NavigationStack의 검색 바 NavigationStack은 `searchable` 수식어를 사용하여 검색 바를 포함할 수 있습니다. 그 서명은 다음과 같습니다: ```swift searchable(...) ```

SwiftUI Dark Mode: 완전 구현 가이드

현재 색상 스킴 감지 SwiftUI는 `@Environment.colorScheme`를 제공하여 앱이 라이트 모드인지 다크 모드인지 감지합니다. ```swift struct ContentView: View { // ... } ```