SwiftUI app life cycle iOS14 where to put AppDelegate code?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
With the iOS 14 SwiftUI app lifecycle, many developers wonder where legacy AppDelegate code should live. The answer is that SwiftUI’s @main App is now the primary entry point, but you can still bridge UIKit delegate behaviors when needed. Push notifications, analytics SDK initialization, deep link handling, and background task registration may still require delegate hooks. A clean architecture keeps lifecycle responsibilities explicit and avoids scattering startup logic across views.
Core Sections
1. Use @main App as primary entry
Basic startup state should be initialized here or injected via environment objects.
2. Bridge AppDelegate with adaptor
For APIs that still require UIApplicationDelegate:
This is the standard migration path for mixed SwiftUI/UIKit lifecycle logic.
3. Scene-level handlers
Use SwiftUI scene handlers for phase-based behavior:
This often replaces older foreground/background delegate methods.
4. Notification and deep-link routing
Keep external-event entry points in delegate/adaptor, then forward into an app-level router/service. This prevents lifecycle APIs from leaking into view code.
5. Testing and modularity
Isolate startup integrations (analytics, crash reporting, remote config) behind protocols. This makes app launch behavior testable and avoids tight coupling to AppDelegate.
6. Migration guidance
During incremental migration:
- keep unavoidable UIKit delegate methods in adaptor
- move app state and navigation logic into SwiftUI layers
- gradually reduce direct delegate dependencies
This yields cleaner long-term architecture.
Validation and production readiness
A reliable implementation is not complete until it is validated under realistic conditions. Add a minimal but representative test matrix that includes normal inputs, edge cases, and malformed data. For UI-focused topics, include at least one scenario for lifecycle or timing behavior (initial load, state transition, and cleanup) so regressions are detected when framework versions change. For infrastructure and tooling topics, run commands against a disposable environment before applying in production and capture expected outputs in documentation. This reduces ambiguity when teammates reproduce steps later.
Instrumentation is equally important. Add structured logs around the critical path, including input shape, selected branch decisions, and failure reasons. Keep logs concise and machine-parseable so alerts and dashboards can surface patterns quickly. If operations are expensive or remote (network, filesystem, container orchestration), include timeout handling and explicit retry policy with backoff. Silent retries without bounds are a common source of hidden incidents.
Finally, document assumptions and compatibility boundaries near the code or article examples: runtime versions, platform requirements, and known behavior differences across environments. Add a lightweight checklist for rollouts that covers dependency pinning, backup/rollback strategy, and smoke checks after deployment. Teams that treat these steps as part of the baseline implementation, not optional polish, usually see fewer production surprises and faster recovery when issues occur.
Common Pitfalls
- Duplicating startup logic in both
@main Appand AppDelegate. - Putting global service initialization inside random views.
- Mixing scene phase handling and delegate callbacks without ownership boundaries.
- Keeping UIKit-era singleton patterns where SwiftUI environment injection is better.
- Ignoring testability of launch-time side effects.
Summary
In iOS 14+ SwiftUI lifecycle, @main App is the main entry point, and @UIApplicationDelegateAdaptor is the right bridge for APIs that still require AppDelegate hooks. Keep lifecycle responsibilities separated: delegate for platform callbacks, SwiftUI for state and UI flow. This structure supports clean migration and maintainable app startup behavior.

