How to Get a Reference to AppDelegate in Swift: From Simple to Advanced
If you've ever written iOS code in Swift, you've likely encountered a situation where you need to access AppDelegate. It seems simple, right? But this question has thousands of views on Stack Overflow, and for good reason. Behind the apparent simplicity lies a whole layer of architectural decisions that affect code performance and maintainability.
In this article, we'll cover not only the classic ways to get a reference to AppDelegate, but also discuss when it's truly necessary and when it's better to look for alternatives. Let's go!
The Classic Way: UIApplication.shared.delegate
The most common and perhaps the simplest way is to use the UIApplication.shared singleton. It looks like this:
if let appDelegate = UIApplication.shared.delegate as? AppDelegate { // Now you have access to AppDelegate appDelegate.someMethod()}This code works, but it has a couple of nuances. First, we explicitly cast the type, which can lead to a crash if delegate turns out to be a different class. Second, this approach creates tight coupling in the code. In the world of modern iOS development, this is considered an anti-pattern, especially if you are using SwiftUI or SceneDelegate.
Optimization: Creating a Safe Wrapper
To avoid writing the type cast every time and to reduce risk, you can create a convenient extension. This not only simplifies the code but also improves its readability:
extension UIApplication { static var appDelegate: AppDelegate? { return shared.delegate as? AppDelegate }}
// Usageif let appDelegate = UIApplication.appDelegate { appDelegate.performTask()}Note: we use static var rather than a computed property each time. This slightly improves performance with frequent calls. The Swift compiler optimizes such constructs, giving you safe access without extra effort.
Alternative Approach: Through UIApplication.shared.delegate?.window??
Sometimes developers try to get AppDelegate through the window chain. It looks like this:
let appDelegate = UIApplication.shared.delegate?.window??.rootViewControllerHonestly, this is not a good practice. First, window can be nil at app launch. Second, such code is hard to read and debug. Performance also suffers — each optional chaining requires additional checks. It's better to use the first method.
When is Access to AppDelegate Really Needed?
Before reaching for UIApplication.shared.delegate, ask yourself: "Do I really need this?" Often, AppDelegate is used for:
- Managing the app lifecycle (launch, background transition, termination)
- Configuring global services (Core Data, Firebase, analytics)
- Handling push notifications and deep linking
But if you just need to pass data between screens or call a service, AppDelegate is the wrong choice. It's better to use Dependency Injection or singletons for specific services.
SwiftUI and AppDelegate: A New Perspective
With the arrival of SwiftUI, the approach to architecture has changed. Now we have @main and the App protocol. But what if you still need access to the old AppDelegate? You can use UIApplicationDelegateAdaptor:
@mainstruct MyApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene { Win