avatar
Published on

How to Access the App Delegate in Swift

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

Sometimes you need to access your app's delegate to retrieve shared state, call methods, or access properties you've added. Here's how to do it from both UIKit and SwiftUI contexts.

Accessing App Delegate in UIKit

In UIKit, access the app delegate through UIApplication.shared.delegate. You'll need to import UIKit and cast to your specific app delegate class:

import UIKit

if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
    // Access your app delegate properties and methods
    appDelegate.someProperty = "value"
    appDelegate.someMethod()
}

Note that AppDelegate here refers to your custom subclass of UIApplicationDelegate, not the protocol itself. If you don't have an app delegate yet, see Adding an App Delegate to a SwiftUI App for setup instructions.

Common Use Case: Accessing App Delegate from SwiftUI

In SwiftUI apps, you often need to access the app delegate to interact with properties or services initialized there. Here's how:

import SwiftUI
import UIKit

struct ContentView: View {
    var body: some View {
        Button("Trigger App Delegate Method") {
            if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
                appDelegate.performBackgroundTask()
            }
        }
    }
}

Why You'd Need This in SwiftUI

Even though SwiftUI uses @UIApplicationDelegateAdaptor, you might need to access the app delegate to:

  • Access shared services: Database managers, network clients, or analytics initialized in the app delegate
  • Call app-wide methods: Trigger operations that affect the entire app
  • Read configuration: Access flags or settings stored at the app level

Here's a practical example with a shared service:

// AppDelegate.swift
import UIKit

class AppDelegate: NSObject, UIApplicationDelegate {
    var networkManager = NetworkManager()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        networkManager.configure()
        return true
    }
}

// In your SwiftUI app
@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

// Accessing from a SwiftUI view
struct DataView: View {
    @State private var data: [String] = []

    var body: some View {
        List(data, id: \.self) { item in
            Text(item)
        }
        .task {
            if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
                data = await appDelegate.networkManager.fetchData()
            }
        }
    }
}

Alternative: Environment Injection

For better SwiftUI integration, consider injecting services through the environment instead of accessing them through the app delegate:

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appDelegate.networkManager)
        }
    }
}

struct DataView: View {
    @EnvironmentObject var networkManager: NetworkManager

    var body: some View {
        // Use networkManager directly
    }
}

This approach is cleaner and more testable, but accessing the app delegate directly remains useful for quick integrations or legacy code.

Important Note

Remember to import UIKit at the top of any file where you access UIApplication.shared.delegate. This is required even in SwiftUI files since you're using UIKit APIs.