iOS Application Scene Delegate VS App Delegate(A talk about Life cycle)

Ario Liyan
6 min readAug 8, 2023

--

Preface

Starting from iOS 13, apps can have multiple windows on iPad, which is super cool and takes iPad multitasking to a whole new level. Before that, apps usually only had one user interface and one window to work with. But Apple had to seriously shake things up to make multi-window support happen, and it forced them to revamp the app and user interface life cycles in a big way.

According to Swift’s documentation

  • In iOS 13 and later, use UISceneDelegate objects to respond to life-cycle events in a scene-based app.
  • In iOS 12 and earlier, use the UIApplicationDelegate object to respond to life-cycle events.

iOS 12 and earlier

On iOS 12 and earlier, the app and user interface life cycles are tightly coupled to each other. When the user taps the app icon, the system creates a process for our app, launches it, and runs the UIApplicationMain() function. This function makes a new instance of the UIApplication class, which is like the root of our app. Every app has just one instance of this class, and we can get to it using the shared class method of UIApplication.

let appDelegate = UIApplication.shared.delegate as! AppDelegate

The UIApplication singleton has a delegate object that conforms to the UIApplicationDelegate protocol. When we start a new project with the Single View App template, Xcode hooks us up with the AppDelegate class, which conforms to the UIApplicationDelegate protocol and is literally the root object of our application.

The UIApplication singleton is like the messenger that tells the application delegate when different events happen in the app’s life cycle, like when it’s done launching or when the system’s about to terminate it. Note that each app only has one UIApplication instance, no matter what version of iOS we’re using. That was true before iOS 13, and it’s still true now.

So, when the system starts our app, the app delegate gets notified through the application(:willFinishLaunchingWithOptions:) and application(:didFinishLaunchingWithOptions:) functions. We usually get our app ready to go in application(_:didFinishLaunchingWithOptions:). That’s where we can set up the user interface by making the app window, or if We’re using storyboards, the window is made for us.

List of events:

func application(UIApplication, willFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool

func application(UIApplication, didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool

func application(UIApplication, didDiscardSceneSessions: Set<UISceneSession>)

func applicationDidBecomeActive(UIApplication)

func applicationWillResignActive(UIApplication)

Tells the delegate that the app is about to become inactive.

func applicationDidEnterBackground(UIApplication)

Tells the delegate that the app is now in the background.

func applicationWillEnterForeground(UIApplication)

Tells the delegate that the app is about to enter the foreground.

func applicationWillTerminate(UIApplication)

Tells the delegate when the app is about to terminate.

func applicationProtectedDataDidBecomeAvailable(UIApplication)

Tells the delegate that protected files are available now.

func applicationProtectedDataWillBecomeUnavailable(UIApplication)

Tells the delegate that the protected files are about to become unavailable.

func applicationDidReceiveMemoryWarning(UIApplication)

Tells the delegate when the app receives a memory warning from the system.

func applicationSignificantTimeChange(UIApplication)

Tells the delegate when there is a significant change in the time.

For more read the documentation page below:

What is a Window

iOS 13 and Later

Starting from iOS 13, our app remains tightly integrated within a single process under system management. Consequently, as our app is bound to a singular process, we operate with a single instance of UIApplication. Accessing the UIApplication singleton remains feasible by utilizing the shared class method of UIApplication.

However the app delegate doesn’t get notified about what’s going on with the user interface life cycle events anymore, and now apps can have multiple interfaces or scenes.

How the user interface is set up, managed, and terminated down is quite different in a scene-based application. The application delegate is no longer responsible for creating and managing the window of the application. That responsibility is on the scene delegate, an object that conforms to the UIWindowSceneDelegate protocol. This implies that any events related to the user interface life cycle, for example, the application entering the foreground or the background, are handled by the scene delegate now.

Now apps can have multiple scenes on an iPad. Each scene has its own unique state going on, with one scene up front and another can be in the background. So, it doesn’t make sense anymore to have the app delegate be in charge of handling the user interface life cycle events. Instead, each scene has its own UIWindowSceneDelegate object that takes care of those events for the scene it’s connected to.

The SceneDelegate provides methods such as scene(_:willConnectTo:options:), sceneWillEnterForeground(_:), sceneDidEnterBackground(_:), and sceneDidDisconnect(_:) to handle various events in the scene lifecycle. These methods allow us to perform necessary setup tasks, update the UI, save the app state, and respond to changes as needed.

SceneDelegate vs. AppDelegate

Responsibilities:

  • AppDelegate: The AppDelegate class has been a crucial part of iOS apps since the early days. It handles the overall lifecycle of our app, including launch, termination, and handling system-level events. It is responsible for setting up the initial app environment, managing app-level data and resources, handling push notifications, and more.
  • SceneDelegate: The SceneDelegate, introduced in iOS 13, focuses specifically on managing the lifecycle and configuration of multiple instances of UI within our app. It handles events related to scenes, such as activation, deactivation, and termination. The SceneDelegate is responsible for setting up the initial UI for each scene and responding to changes within those scenes.

Single vs. Multiple Instances:

  • AppDelegate: Traditionally, the AppDelegate was responsible for managing a single instance of UI. It provided the app’s window object that acted as the root view for the entire app.
  • SceneDelegate: With the introduction of scenes, the SceneDelegate allows for multiple instances of UI within a single app. Each scene has its own window object, and the SceneDelegate is responsible for managing the UI and events specific to that scene.

Scene Lifecycle:

  • AppDelegate: The AppDelegate handles the overall app lifecycle, including events like application launch, termination, backgrounding, and foregrounding.
  • SceneDelegate: The SceneDelegate focuses on managing the lifecycle of individual scenes. It provides methods that are specifically invoked when a scene is created, activated, deactivated, or terminated. This allows for more granular control over each scene’s behavior and appearance.

UISceneSession:

  • AppDelegate: The AppDelegate uses the application(_:didFinishLaunchingWithOptions:) method to initialize the app and configure its initial state.
  • SceneDelegate: The SceneDelegate uses the scene(_:willConnectTo:options:) method to configure a new scene when it is first created. It receives a UISceneSession object containing information about the scene, allowing us to customize the scene's appearance and behavior based on its context.

Scene Configuration

The SceneDelegate provides methods to configure the appearance and behavior of each scene. For example, the scene(_:willConnectTo:options:) method allows us to set up the initial UI and provide the appropriate view controller for the scene. We can customize various aspects of the scene, such as the status bar style, window level, and more. This level of customization is beneficial when we want different scenes to have distinct configurations within the same app.

Scene Activation and Deactivation

When a scene is activated, the SceneDelegate’s sceneDidBecomeActive(_:) method is called. This is where we can respond to the scene becoming the foreground scene, update the UI, and resume any necessary tasks. Conversely, when a scene is deactivated, the sceneWillResignActive(_:) method is invoked. We can use this method to pause ongoing tasks, save data, or perform any cleanup required when the scene moves to the background.

Handling Multiple Windows

In addition to managing multiple scenes, the SceneDelegate also supports multiple windows within a scene. Each scene can have multiple windows, allowing for more complex UI setups. The SceneDelegate provides methods such as scene(_:openURLContexts:) and scene(_:continue:) to handle deep linking and state restoration when our app is launched with specific URLs or user activities. This enables us to handle different entry points and navigation flows within our app.

Adapting to Changes

The SceneDelegate allows our app to adapt to changes in the user interface. For example, when the device is rotated or the user activates Slide Over or Split View on iPad, the system may create or modify existing scenes. The SceneDelegate provides methods such as sceneWillEnterForeground(_:) and sceneDidEnterBackground(_:) to handle these interface changes. We can update the UI, adjust layout constraints, or perform any necessary adjustments when the scene transitions between foreground and background states.

Interaction with App Delegate

Although the SceneDelegate handles scene-related events, it still interacts with the AppDelegate when necessary. The AppDelegate retains its responsibility for app-level events and behaviors. For example, the AppDelegate’s application(_:didFinishLaunchingWithOptions:) method is called when the app is initially launched, even before any scenes are created. We can use this method to perform global app setup tasks, initialize services, or set up shared resources that are not specific to a particular scene.

Summary

The SceneDelegate in Swift complements the AppDelegate by managing the lifecycle and configuration of individual scenes within an app. It allows for customization of each scene’s appearance and behavior, handles activation and deactivation events, supports multiple windows within scenes, and adapts to changes in the user interface. The SceneDelegate and AppDelegate work together to provide a seamless and flexible user experience in modern iOS apps.

--

--

Ario Liyan

As an iOS developer with a passion for programming concepts. I love sharing my latest discoveries with others and sparking conversations about technology.