The App Launch Sequence
There are several phases involved in launching an application, most of which the system handles automatically. The operating system calls methods in your app delegate during the launch sequence, allowing you to prepare your app for user interaction. The system provides some initial instances and an initial interface to run.
The Entry Point
When the app launches, the system knows where to find compiled binary within the app bundle.
Thanks to info.plist
in the same bundle, this file has an executable file key(CFBundleExecutable
) whose value is the name of the app’s binary.
The system loads the binary and links any required frameworks. Now it needs to execute a code from the app’s binary to launch it. But where?
The answer would be obvious if this app were an Objective-C program.
Objective-C is derived from C programing language, so the entry point is main function. Objective-C project would have a main.m
file containing the main function:
_10int main(int argc, char *argv[]) {_10 @autoreleasepool {_10 return UIApplicationMain(argc, argv, nil,_10 NSStringFromClass([AppDelegate class]));_10 }_10}
The main function performs two tasks:
- It creates an environment for memory management, thanks to
@autoreleasepool
. - It executes the
UIApplicationMain
function, which enables your application to use its bootstraps to set itself up and running.
If our app is Swift program, it has no main
function. Rather, Swift has a specific attribute: @main
. You can see it in the AppDelegate.swift
file where AppDelegate class is defined.
_10@main_10class AppDelegate: UIResponder, UIApplicationDelegate {_10 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {_10 return true_10 }_10}
Basically, this property handles all of the functionality Objective-C main.m file: it creates an entry point that executes UIApplicationMain
to launch the app.
Note: Swift 5.3 introduced the @main term; this attribute was formerly known as @UIApplicationMain.
It would be very uncommon, but you can create a main.swift
file like Objective-C main file.
Delete the @main
attribute and instead use main file. This file, main.swift, gets special treatment, so the name is critical.
This file has also another special ability, it will execute code at the top level of the file, outside any function body. Other swift files, all executable code lives in a function. From a specific angle, computer programs just calls functions in the related files. Swift equivalent of the Objective-C call to UIApplicationMain, like this:
_10import UIKit_10UIApplicationMain(_10 CommandLine.argc, CommandLine.unsafeArgv, nil,_10 NSStringFromClass(AppDelegate.self)_10)
You are calling the UIApplicationMain function in a iOS application. The main task of your application is this function call. All your application really does is make one massive call to UIApplicationMain.
SwiftUI App Life Cycle
By default, when you make a new SwiftUI application, there is no AppDelegate
class in the application that is generated. It has been replaced by an struct that conforms to the App
protocol. Similar to how SwiftUI creates structs for views, it also use struct for launch process with a @main
attribute.
_10import SwiftUI_10_10@main_10struct SwiftUIApp: App {_10 var body: some Scene {_10 WindowGroup {_10 ContentView()_10 }_10 }_10}
You might need to revert to the previous version of the UIApplicationDelegate ability - possibly to handle push notification registration or or 3rd party library integration(Firebase etc.).
First, create a AppDelegate class that inherits from “NSObject” and conforms to the “UIApplicationDelegate” protocol, like this:
_12class AppDelegate: NSObject, UIApplicationDelegate {_12 func application(_ application: UIApplication, _12 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {_12 configureApp()_12 return true_12 }_12_12 private func configureApp() {_12 // Add any configuration steps here._12 print("Application launched!")_12 }_12}
After that, you can add a reference to the AppDelegate file in your App.swift file with UIApplicationDelegateAdaptor
property wrapper.
_10@main_10struct SwiftUIApp: App {_10 @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate_10_10 var body: some Scene {_10 WindowGroup {_10 ContentView()_10 }_10 }_10}
App State Transitions
The state transitions can be tracked by implementing UIApplicationDelegate callbacks with AppDelegate or SceneDelegate, it depends on how new the project is.
Pre-warming
With iOS15 and later, the system might decide to pre-warm your app before the user tries to open it.
This process minimizes the length of time the user has to wait before the app is usable.
Pre-warming runs the launch sequence of an application until main()
calls UIApplicationMain
methods, but not beyond that point.
This helps the system to build and cache any low-level structures that are needed.
Once your app is prewarmed by the system, its launch sequence is halted until the app starts or the system kills the prewarmed app from memory in order to reclaim resources. The system can prewarm your app after every device reboot.
If your application runs code before the calling UIApplicationMain
methods, such as load(), be careful when assuming which resources and services are available.
For instance, keychain items could not be available because their data protection policies need an unlocked device status.
Key Points
- Entry Point: Objective-C programs have a traditional main function, while Swift programs use the
@main
attribute or amain.swift
file to initiate the application launch sequence. - SwiftUI App Lifecycle: SwiftUI apps replace the traditional
AppDelegate
with a struct conforming to theApp
protocol, simplifying the initialization process with a@main
attribute. - Pre-warming: iOS 15 introduced app pre-warming, which initiates parts of the launch sequence to reduce user wait times.
- Executable File Identification: The system identifies the executable file of an app through the info.plist file, crucial for locating and launching the application's binary.