Working with App Lifecycle
1. Understanding App States
| State | Description | Key Methods | Notes |
|---|---|---|---|
| Not Running | App is not running or has been terminated. | - | App has no memory allocated. |
| Inactive | App is running in the foreground but not receiving events. | applicationWillResignActive(_:) |
Temporary state, e.g., incoming phone call. |
| Active | App is running in the foreground and receiving events. | applicationDidBecomeActive(_:) |
Primary state for user interaction. |
| Background | App is running in the background but not suspended. | applicationDidEnterBackground(_:) |
App can perform limited tasks, e.g., location updates. |
| Suspended | App is in the background and not executing code. | applicationWillEnterForeground(_:) |
App is suspended but can be reactivated. |
Example: App State Transition Handling
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print("App launched")
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
print("App entered background")
}
func applicationWillEnterForeground(_ application: UIApplication) {
print("App will enter foreground")
}
func applicationDidBecomeActive(_ application: UIApplication) {
print("App became active")
}
func applicationWillResignActive(_ application: UIApplication) {
print("App will resign active")
}
}
2. Implementing App Delegate Methods
| Method | Description | Notes |
|---|---|---|
| application(_:didFinishLaunchingWithOptions:) | Called when the app finishes launching | Most common place to set up initial configuration |
| applicationDidBecomeActive(_:) | Called when the app becomes active | App is ready for user interaction |
| applicationWillResignActive(_:) | Called when the app is about to resign active status | App is transitioning to background or becoming inactive |
| applicationDidEnterBackground(_:) | Called when the app enters background | App is now in background state, but still running |
| applicationWillEnterForeground(_:) | Called when the app is about to enter foreground | App is about to become active again |
| applicationDidReceiveMemoryWarning(_:) | Called when the app receives a memory warning | App should release any non-essential resources |
| applicationWillTerminate(_:) | Called when the app is about to terminate | App is being terminated, not suspended |
Example: Implementing App Delegate Methods
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Setup code here
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
// App is now active
}
func applicationWillResignActive(_ application: UIApplication) {
// App is about to become inactive
}
func applicationDidEnterBackground(_ application: UIApplication) {
// App is now in background
}
func applicationWillEnterForeground(_ application: UIApplication) {
// App is about to enter foreground
}
func applicationDidReceiveMemoryWarning(_ application: UIApplication) {
// Handle memory warning
}
func applicationWillTerminate(_ application: UIApplication) {
// App is about to terminate
}
}
3. Using Scene Delegates
| Property | Description | Notes |
|---|---|---|
| scene | The scene object associated with the app lifecycle event. | Used to access scene-specific configuration and state. |
| connectionOptions | Options provided when connecting to the scene. | Includes information about how the scene was launched or connected. |
Example: Scene Delegate Implementation
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Configure the window and root view controller
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let rootViewController = UIViewController()
rootViewController.view.backgroundColor = .systemBackground
window?.rootViewController = rootViewController
window?.makeKeyAndVisible()
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called when the scene disconnects from the session
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene becomes active
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will resign active
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called when the scene will enter foreground
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called when the scene enters background
}
}
Note: Scene delegates are used in iOS apps that support multiple scenes, such as split-screen multitasking or window management.
4. Handling App Launch
| Method | Description | Notes |
|---|---|---|
| application(_:didFinishLaunchingWithOptions:) | Called when the app finishes launching | Entry point for app initialization |
| application(_:didFinishLaunchingWithOptions:) | Called when the app finishes launching | Entry point for app initialization |
Example: App Launch Configuration
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Custom initialization code
print("App launched successfully")
return true
}
Note: This method is called only once during the app's lifecycle.
5. Handling App Termination
| Method | Description | Notes |
|---|---|---|
| applicationWillTerminate(_ application: UIApplication) | Called when the app is about to terminate | Not guaranteed to be called; may not be invoked if the app is force-quit |
Example: App Termination Handler
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillTerminate(_ application: UIApplication) {
// Save data to disk or clean up resources
print("App is about to terminate")
}
}
Note: The
applicationWillTerminate method is not called when the app is suspended or force-quit by the user.6. Managing Background Tasks
| Task Type | Description | API | Notes |
|---|---|---|---|
| Background Processing | Execute tasks while app is in background | BackgroundTasks |
Available from iOS 13+ |
| Long Running Tasks | Execute tasks that take longer than the typical background time | UIApplication |
Deprecated in iOS 13+ |
| Background App Refresh | Allow app to refresh content in background | UIBackgroundFetch |
Controlled by user settings |
Example: Requesting Background Task
import BackgroundTasks
func scheduleBackgroundTask() {
let request = BGProcessingTaskRequest(identifier: "com.example.background")
request.earliestBeginDate = Date().addingTimeInterval(300) // 5 minutes
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Failed to schedule background task: \(error)")
}
}
Example: Handling Background Task
func handleBackgroundTask(_ task: BGTask) {
task.expirationHandler = {
task.cancel()
}
// Perform background work here
DispatchQueue.global().async {
// Simulate work
sleep(2)
task.finish()
}
}
Note: Background tasks must be scheduled before app enters background state.
Warning: Background tasks are not guaranteed to run at the scheduled time.
| Task Identifier | Earliest Begin Date | Expiration Handler | Finish |
|---|---|---|---|
BGProcessingTaskRequest |
Date().addingTimeInterval(300) |
task.expirationHandler |
task.finish() |
7. Using Background Fetch
| Property | Value | Description |
|---|---|---|
| backgroundFetchInterval | UIBackgroundFetchIntervalMinimum |
Minimum time interval between background fetch operations (15 minutes) |
| backgroundFetchInterval | UIBackgroundFetchIntervalNever |
Disables background fetch |
Example: Configure Background Fetch
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
application.setMinimumBackgroundFetchInterval(UIBackgroundFetchIntervalMinimum)
return true
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// Fetch data in background
fetchData { success in
if success {
completionHandler(.newData)
} else {
completionHandler(.noData)
}
}
}
func fetchData(completion: @escaping (Bool) -> Void) {
// Simulate network request
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
completion(true)
}
}
}
Note: Background fetch is not guaranteed to run at the specified interval. The system may delay or skip it based on battery life, network conditions, and user behavior.
8. Using Background URLSessions
| Property | Value | Description |
|---|---|---|
| backgroundSessionConfiguration | URLSessionConfiguration.background |
Creates a configuration for background sessions |
| sessionIdentifier | String |
Unique identifier for the background session |
| timeoutIntervalForRequest | TimeInterval |
Maximum time to wait for a request to complete |
| timeoutIntervalForResource | TimeInterval |
Maximum time to wait for a resource to complete |
Example: Creating a Background URLSession
let config = URLSessionConfiguration.background(
identifier: "com.example.backgroundSession"
)
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
Example: Handling Background Session Events
func urlSession(
_ session: URLSession,
didCompleteWithError error: Error?
) {
if let error = error {
print("Background session error: \(error)")
} else {
print("Background session completed successfully")
}
}
Note: Background sessions are only available on iOS 7.0 and later.
Warning: Background sessions must be configured with a unique identifier to persist across app launches.
9. Implementing State Restoration
State restoration allows iOS apps to restore their UI and data when the app is relaunched after being terminated. This feature is particularly useful for apps that manage complex UI states or user sessions.
| Property | Description | Notes |
|---|---|---|
| restorableState | Boolean flag to enable state restoration | Must be set in application(_:willFinishLaunchingWithOptions:) |
| restorationIdentifier | Unique identifier for state restoration | Used to restore specific view controllers or data |
| restorationClass | Custom class that handles restoration logic | Implement UIStateRestoring protocol |
Example: Enabling State Restoration
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
self.restorableState = true
return true
}
Example: Implementing UIStateRestoring
class MyViewController: UIViewController, UIStateRestoring {
@IBOutlet weak var textField: UITextField!
override func encodeRestorableState(with coder: NSCoder) {
super.encodeRestorableState(with: coder)
coder.encode(textField.text, forKey: "textFieldText")
}
override func decodeRestorableState(with coder: NSCoder) {
super.decodeRestorableState(with: coder)
textField.text = coder.decodeObject(forKey: "textFieldText") as? String
}
}
Note: State restoration is not guaranteed to work in all scenarios, particularly when the app is terminated by the system due to memory pressure.
Warning: Ensure that sensitive data is not stored in the restoration state to prevent security vulnerabilities.
10. Monitoring Memory Warnings
| Method | Description | Notes |
|---|---|---|
| applicationDidReceiveMemoryWarning(_ application: UIApplication) | Called when the app receives a memory warning | Deprecated in iOS 13. Use didReceiveMemoryWarning in UIResponder |
| didReceiveMemoryWarning() | Override in UIResponder subclasses to handle memory warnings |
Available since iOS 2.0 |
Example: Handling Memory Warnings in a View Controller
class MyViewController: UIViewController {
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Clean up cached data or images
if isViewLoaded {
// Clear any cached resources
cachedImages = nil
}
}
}
Note: Memory warnings are not guaranteed to be sent, but they should be handled gracefully to prevent app termination.