Skip to main content

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.

Was this article helpful?