| name | ios-launch-performance |
| description | Use this skill when diagnosing iOS app launch performance, startup regressions, first-frame readiness, or early responsiveness. Covers pre-main/dyld work, AppDelegate/SceneDelegate, SwiftUI App startup, launch orchestration, SDK initialization, and launch measurement. Do not use for general performance unless the code runs on the launch path. |
iOS Launch Performance
Use this skill to review the path from an app launch request to first visible UI and early responsiveness.
Focus on work that happens:
- before
main
- during UIKit or SwiftUI startup
- inside
UIApplicationDelegate, UISceneDelegate, or SwiftUI App
- during root UI creation
- before the first visible frame
- before the first meaningful interaction
- during early post-launch work that still affects user-perceived readiness
This is not a general iOS performance skill. Use it only when the issue is launch-specific or when the code runs on the launch path.
Core Model
Treat launch as a pipeline with separate phases:
- Process creation and system preparation
- dyld loading, binding, fixups, runtime registration, and static initialization
- UIKit or SwiftUI runtime startup
- App-level initialization in
UIApplicationDelegate, UISceneDelegate, or SwiftUI App
- Launch orchestration and dependency setup
- Root UI construction, layout, drawing, and first frame commit
- Early post-launch work that affects responsiveness
- Later feature-specific or maintenance work
Do not optimize blindly. First identify which phase is expensive, then recommend changes that move, remove, lazy-load, parallelize, serialize, or measure that specific work.
When to Use This Skill
Use this skill when the task involves:
- slow app launch
- startup regressions
- cold, warm, or prewarmed launch
- resume-vs-launch confusion
- first-frame readiness
- early responsiveness after launch
- pre-main or dyld work
- Objective-C
+load, +initialize, constructor functions, or static initialization
- AppDelegate or SceneDelegate startup work
- SwiftUI
@main App, WindowGroup, root view setup, or environment injection
- dependency container setup during launch
- launch orchestrators or ordered startup steps
- third-party SDK initialization during launch
- framework linking strategy when launch cost is suspected
- launch metrics from Instruments, XCTest, MetricKit, or Xcode Organizer
Do not use this skill for:
- general scrolling performance
- memory leaks unrelated to launch
- rendering optimization unrelated to first frame
- networking performance outside startup
- broad architecture review unless the architecture affects the launch path
Launch Scenario Classification
Before giving advice, classify what is being measured:
- Cold launch: the app process is not resident and little launch-related state is already warm.
- Warm launch: the app still starts a new process, but parts of system state, caches, or pages may already be warm.
- Prewarmed launch: the system may have prepared part of the launch path before the user explicitly opens the app.
- Resume / already-running return: the app process already exists and returns from background or suspension.
- First install / first run / update launch: launch includes extra setup such as migrations, cache creation, permissions, account/bootstrap work, or version-specific setup.
- Unknown: the measurement setup does not clearly separate the above cases.
Do not compare cold launch, warm launch, prewarmed launch, first-run launch, update launch, and resume as one metric.
Resume is not a full launch investigation unless the task explicitly asks about foregrounding latency.
Investigation Workflow
1. Locate the launch path
Identify code that executes before first frame or before first meaningful interaction.
Inspect:
- app delegate
- scene delegate
- SwiftUI
App
- root scene construction
- root view/model creation
- dependency container setup
- global/static initialization
- launch orchestrators
- SDK startup
- linked framework initialization
- first-screen routing and state restoration
2. Classify the slow phase
Classify the likely phase before recommending fixes:
- dyld/pre-main
- Objective-C or Swift runtime/static initialization
- app delegate startup
- scene delegate startup
- SwiftUI app/root view initialization
- launch orchestration or dependency setup
- root UI construction and first-frame rendering
- early post-launch responsiveness
- measurement ambiguity
If the available evidence is not enough to classify the phase, say so and recommend the next measurement step.
3. Classify startup work by necessity
For each startup task, classify it as:
- required before first frame
- required before first interaction
- needed soon after launch
- needed only after authentication/session state is known
- needed only by a later feature
- background maintenance
Work that is not required before first frame or first interaction should not block launch unless there is a correctness reason.
4. Build a dependency view
If launch has ordered steps, SDK setup calls, service registrations, or a launch orchestrator, identify:
- which steps are truly required for the first visible UI
- which steps are required before the first meaningful interaction
- which steps can run independently
- which steps must stay ordered
- which steps touch the main thread or shared mutable state
- which failures must block launch
- which dependency chain forms the longest critical path
Treat comments, fragile ordering, and institutional knowledge as risk. Prefer explicit dependencies over relying on call order.
5. Look for hidden eager work
Check for launch work hidden in:
- Objective-C
+load
- Objective-C
+initialize
- C/C++ constructor functions
- C++ global objects with constructors
- Swift globals or static properties
- eager singletons
- dependency graph construction
- SDK auto-registration
- dynamic framework startup
- synchronous file I/O
- database opening or migration
- keychain-heavy work
- networking or remote configuration
- large decoding/parsing
- blocking locks, semaphores, dispatch groups, or synchronous waits on the main thread
Treat hidden initialization as launch-critical until measurement proves otherwise.
6. Recommend targeted changes
Prefer changes that directly shorten or unblock the launch path:
- remove unnecessary launch work
- lazy-load feature-specific services
- defer noncritical work until after visible UI or first interaction
- split launch-critical state from secondary app state
- make startup dependencies explicit
- replace hidden static initialization with explicit or lazy initialization
- move blocking work off the main thread only when safe and useful
- use bounded parallelism only after auditing dependencies, shared state, isolation, and failure behavior
- review linking strategy only when evidence points to pre-main or dyld cost
- shrink the first usable surface instead of initializing the whole application graph before display
Do not recommend broad rewrites unless the launch path cannot be safely improved with smaller changes.
7. Require validation
Every recommendation should include a validation path.
Use:
- Instruments App Launch for phase-level diagnosis
- Time Profiler for CPU-heavy startup paths
- dyld-related tools or logs when pre-main work is suspected
os_signpost or equivalent markers for app-specific startup phases
- XCTest launch metrics for repeatable local or CI regression checks
- MetricKit or Xcode Organizer for production distributions
Prefer release-like builds, real devices, stable test data, repeated runs, and older supported hardware.
High-Value Decision Rules
- Treat roughly 400 ms to first visible frame as an aggressive user-experience target, not as a watchdog threshold and not as a pre-main-only budget.
- Do not blame dyld by default. Slow launch can come from pre-main work, app initialization, launch orchestration, root UI creation, first-frame rendering, synchronous I/O, or early post-launch blocking.
- Treat
+load, constructor functions, and static initialization with side effects as launch-critical until measurement proves otherwise.
- Prefer explicit setup, lazy initialization, or scoped one-time initialization over work hidden in load-time hooks.
- Do not present
+initialize as a universal fix. It can help in some legacy Objective-C code, but explicit or lazy initialization is usually clearer in modern code.
- Do not recommend converting all modules to static linking. Consider launch cost, build time, binary size, duplicate symbols, resource packaging, SDK distribution, debugging, and mergeable libraries.
- Do not use arbitrary framework-count limits. More dynamic frameworks can increase launch work, but the real cost must be measured.
- Do not parallelize launch steps until dependencies, shared state, actor isolation, main-thread requirements, and failure behavior are explicit.
- Do not block the main thread while waiting for parallel startup work unless the code is proven safe, bounded, and required before launch can continue.
- Treat unsafe parallelism as a correctness risk even when it improves a local benchmark.
- Optimize the longest required dependency chain, not only the largest individual startup step.
- Do not assume that queueing work asynchronously on the main queue guarantees it runs after the first frame.
- Do not assume SwiftUI
.task is always post-render or harmless. It is lifecycle-bound async work and can still affect early responsiveness.
- Do not rely on Debug builds, simulator-only runs, or a single modern device when judging launch performance.
- Do not use production launch histograms alone to identify the local bottleneck. Use them to prioritize and verify trends.
Code Review Checklist
When reviewing launch-related code, check these areas first.
Pre-main and runtime initialization
Look for +load, constructor functions, C++ global constructors, expensive Swift globals/statics, eager runtime hooks, Objective-C category-heavy modules, and dynamic frameworks with startup-time initializers.
Read references/pre-main-dyld-and-static-initializers.md when this area is relevant.
Launch orchestration and dependency graph
Look for long ordered startup sequences, implicit dependencies, startup comments that encode required ordering, dependency containers built synchronously, unsafe parallelism, blocking waits, unclear failure behavior, and first-screen code that assumes the whole app graph is ready.
Read references/launch-orchestration-and-dependency-graph.md when this area is relevant.
AppDelegate, SceneDelegate, and first frame
Look for synchronous dependency setup, unconditional SDK initialization, database opening or migration, keychain access, synchronous networking, heavy root view model construction, duplicate app/scene setup, and expensive first-screen rendering.
Read references/appdelegate-scenedelegate-and-first-frame.md when this area is relevant.
SwiftUI App startup
Look for heavy work in App.init, root Scene construction, root view initialization, eager observable model creation, environment injection, .task, .onAppear, scenePhase, and @UIApplicationDelegateAdaptor.
Read references/swiftui-app-launch.md when this area is relevant.
Third-party SDKs
Every SDK that starts during launch must justify why it needs to run before first frame or first interaction.
Classify SDKs as launch-critical, first-interaction required, post-first-frame acceptable, feature-specific and lazy, or background-only.
Be careful with blanket deferral. Crash reporting, security, deep linking, attribution, push routing, remote config, and feature flags can have correctness requirements.
Read references/third-party-sdks-at-launch.md when this area is relevant.
Measurement
When measurements are noisy, clarify:
- device model and OS version
- Debug vs Release/Profile configuration
- simulator vs physical device
- cold/warm/prewarmed/resume classification
- first install, update launch, or returning-user launch
- network and account state
- app data size
- authenticated vs unauthenticated launch
- test iteration count and variance
Read references/metrics-instruments-xctest-metrickit.md when measurement setup or interpretation is relevant.
Reference Routing
Use reference files only when the task needs extra detail.
- Read
references/launch-taxonomy-and-targets.md when the task involves cold/warm/prewarmed/resume terminology, first-frame targets, first install/update launch classification, or measurement setup.
- Read
references/pre-main-dyld-and-static-initializers.md when the task involves dyld, pre-main, +load, +initialize, constructor functions, Objective-C categories, runtime registration, or static initialization.
- Read
references/linking-strategy.md when the task involves dynamic frameworks, static libraries, mergeable libraries, modularization, launch-time linking trade-offs, binary layout, or order-file considerations.
- Read
references/launch-orchestration-and-dependency-graph.md when the task involves launch steps, critical path modeling, explicit dependencies, safe parallelism, race/deadlock risks, failure handling, or longest-chain optimization.
- Read
references/appdelegate-scenedelegate-and-first-frame.md when the task involves UIApplicationDelegate, UISceneDelegate, dependency setup, root UI creation, first-frame readiness, or main-thread startup work.
- Read
references/swiftui-app-launch.md when the task involves SwiftUI App, WindowGroup, root view setup, observable state, .task, .onAppear, scenePhase, @UIApplicationDelegateAdaptor, or environment initialization.
- Read
references/third-party-sdks-at-launch.md when the task involves analytics, crash reporting, ads, attribution, remote config, push, feature flags, security SDKs, or vendor initialization strategy.
- Read
references/metrics-instruments-xctest-metrickit.md when the task involves Instruments, Time Profiler, signposts, XCTest launch metrics, MetricKit, Xcode Organizer, CI baselines, or production monitoring.
Do not read all references by default.
Output Format
When reviewing code or diagnosing a launch report, return the following sections.
Launch classification
State whether the issue appears to involve cold launch, warm launch, prewarmed launch, first install/update launch, resume, or unknown.
Mention measurement ambiguity if present.
Suspected phase
Identify the most likely phase:
- pre-main
- static initialization
- app delegate
- scene setup
- SwiftUI root setup
- launch orchestration
- first-frame rendering
- early post-launch responsiveness
- measurement/setup issue
Critical path
Identify the required startup chain if enough information is available.
Mention hidden ordering, implicit dependencies, or unknown dependencies when they block safe optimization.
Findings
List concrete risks found in the code, architecture, metrics, or trace.
Avoid generic advice not connected to evidence.
Recommended changes
Group recommendations by priority:
- High-confidence launch-path fixes
- Dependency/orchestration fixes
- Measurement or instrumentation needed
- Optional architectural cleanup
Validation
Explain how to verify the change locally and in production.
Include the expected metric, trace area, or startup phase that should improve.
Non-Goals
Do not use this skill for:
- general scrolling performance
- memory leaks
- rendering optimization unrelated to app startup
- networking performance outside launch
- broad app architecture review unrelated to startup
- generic SwiftUI review unless the code affects launch, first frame, or early responsiveness