Suspended — qu'est-ce que c'est, le gel d'application en arrière-plan iOS

Auteur : IT Sectr Publié le : 2026-03-03 Temps de lecture : 11 min

Suspended — un état suspendu du cycle de vie de l'application iOS dans lequel l'application est gelée en mémoire mais n'exécute pas de code. Nous montrons comment fonctionne Suspended, quels risques le gel d'application en arrière-plan comporte, comment iOS gère le déchargement des applications Suspended et comment implémenter state restoration pour une récupération transparente après un retour de Suspended.

Points clés

  • Suspended — l'application est gelée en mémoire, le code n'est pas exécuté, la pile d'UI est préservée
  • iOS Suspended — un état unique qui n'existe pas dans Android ; le processus existe mais n'est pas actif
  • Déchargement — en cas de faible mémoire, les applications Suspended sont supprimées en premier, les données en mémoire sont perdues
  • State Restoration — mécanisme iOS pour sauvegarder et restaurer la pile d'UI après le déchargement
  • didEnterBackground — la dernière méthode garantie d'être appelée avant Suspended

Suspended — qu'est-ce que cet état

Suspended est un état du cycle de vie de l'application iOS dans lequel l'application réside dans la RAM de l'appareil mais n'exécute aucun code. C'est l'état final avant la terminaison complète : l'application passe de Background à Suspended après avoir terminé toutes les tâches en arrière-plan ou après l'expiration d'un délai. Dans Suspended, l'application est complètement gelée — tous les threads sont suspendus, les minuteries ne fonctionnent pas et il n'y a aucune activité réseau.

Suspended est une caractéristique unique d'iOS, absente du cycle de vie standard d'Android. La raison réside dans les différentes architectures de gestion des processus. iOS préserve l'image de l'application en mémoire (semblable à la mise en veille prolongée sur desktop) afin que lorsque l'utilisateur revient, l'interface puisse être instantanément restaurée sans démarrage à froid. Android n'a pas de Suspended — un processus existe et peut exécuter du code (Background) ou est terminé (Not Running), bien qu'Android puisse suspendre l'exécution des threads via LMK.

Pour l'utilisateur, Suspended ressemble à une restauration instantanée : il bascule entre les applications via l'App Switcher, et chaque application s'ouvre là où il l'a laissée. Cela crée l'illusion que toutes les applications fonctionnent simultanément. En réalité, la plupart d'entre elles sont gelées dans Suspended. Un démarrage à chaud depuis Suspended est plusieurs fois plus rapide qu'un démarrage à froid depuis Not Running, car le code est déjà chargé en mémoire.

Comment le système gère Suspended

iOS surveille l'état de toutes les applications et décide de décharger les applications Suspended en fonction de la mémoire disponible. Lorsque la mémoire est faible, le système commence à décharger les applications Suspended, en commençant par celles qui sont dans cet état depuis le plus longtemps. Si la mémoire est toujours insuffisante, le système fait passer les applications de Background et Inactive à Suspended avec déchargement ultérieur. Ce processus est complètement transparent pour l'utilisateur — il voit simplement l'icône de l'application dans l'App Switcher, qui au toucher lance un démarrage à froid.

CaractéristiqueSuspended (iOS)Background (iOS)Background (Android)
Exécute du codeNonOui (limité)Oui (limité)
En mémoireOuiOuiOui
Consommation CPU0%FaibleFaible
Démarrage à chaudOui — restauration instantanéeOui — via InactiveNon — le processus a pu être tué
DélaiNon — peut rester en mémoire pendant des heures~30 secondes (après beginBackgroundTask)Dépend de la version de l'API
Déchargement par le systèmeEn cas de faible mémoireEn cas de mémoire critiqueLMK (Low Memory Killer)
Retour au travailDepuis l'App Switcher — instantanémentDepuis l'App Switcher — via InactiveDémarrage à froid
State RestorationRecommandéNon requisSavedStateHandle

Suspended dans iOS : le mécanisme de gel

Dans iOS, Suspended est atteint automatiquement après la fin de toutes les tâches en arrière-plan. Le système appelle applicationDidEnterBackground, donne du temps pour exécuter beginBackgroundTask (environ 30 secondes), puis suspend de force tous les threads et fait passer l'application en Suspended. Les objets en mémoire sont préservés, mais aucun code n'est exécuté — l'application est gelée dans son état actuel.

Un point crucial : applicationDidEnterBackground est la dernière méthode garantie d'être appelée avant Suspended. Après cela, l'application ne reçoit aucune notification concernant le déchargement de la mémoire. Si l'utilisateur ou le système tue l'application pendant qu'elle est en Suspended, ni applicationWillTerminate ni applicationDidEnterBackground ne sont appelés à nouveau. Par conséquent, toute sauvegarde de données doit avoir lieu dans applicationDidEnterBackground, pas dans applicationWillTerminate.

swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // Dernier appel garantie avant Suspended
    func applicationDidEnterBackground(_ application: UIApplication) {
        // Sauvegarder tout ce qui doit survivre au déchargement de mémoire
        savePersistentState()
        saveNavigationStack()

        // Demander du temps supplémentaire si nécessaire
        let task = application.beginBackgroundTask {
            application.endBackgroundTask(task)
        }
    }

    // Retour de Suspended — démarrage à chaud
    func applicationWillEnterForeground(_ application: UIApplication) {
        // L'application était en Suspended, reprise du travail
        print("Retour de Suspended ou Background")
    }

    // Restauration complète après déchargement de mémoire
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Si c'est un démarrage à froid après déchargement de Suspended —
        // restaurer state restoration
        return true
    }

    private func savePersistentState() {
        UserDefaults.standard.set(Date(), forKey: "lastActiveDate")
    }

    private func saveNavigationStack() {
        guard let rootVC = window?.rootViewController else { return }
        // Sauvegarder la pile de navigation actuelle
        if let navController = rootVC as? UINavigationController {
            let vcClasses = navController.viewControllers.map { type(of: $0) }
            UserDefaults.standard.set(vcClasses.map { NSStringFromClass($0) }, forKey: "navStack")
        }
    }
}

Le code montre le traitement crucial de Suspended sur iOS. applicationDidEnterBackground est le dernier appel garantie. Toute sauvegarde de données doit avoir lieu ici : état utilisateur, pile de navigation, brouillons, minuteries. applicationWillEnterForeground est appelé lors du retour de Suspended ou Background. didFinishLaunchingWithOptions — uniquement au démarrage à froid, lorsque l'application a été déchargée de la mémoire après Suspended.

Suspended dans Android — existe-t-il un analogue

Dans Android, il n'existe pas d'analogue direct du Suspended d'iOS. Android ne gèle pas les applications en mémoire tout en préservant le contexte d'exécution. Au lieu de cela, Android maintient le processus en arrière-plan ou le termine. Cependant, sous Android 11+ (API 30), un mécanisme appelé App Freezer a été introduit, qui suspend l'exécution des processus en arrière-plan à l'aide du signal SIGSTOP. C'est fonctionnellement similaire à Suspended, mais avec des différences importantes.

App Freezer fait partie du système de gestion de la mémoire d'Android. Lorsqu'une application est longtemps en arrière-plan sans notifications actives, le système lui envoie SIGSTOP, suspend tous les threads. Lorsque l'application revient au premier plan, SIGCONT est envoyé et l'exécution reprend. La principale différence avec iOS : App Freezer ne garantit pas la préservation de l'état — les données en mémoire peuvent être perdues si le processus est tué pendant le gel.

Sous Android, il est recommandé d'utiliser SavedStateHandle dans ViewModel pour la préservation automatique de l'état lors de toute terminaison de processus. SavedStateHandle sauvegarde les données dans un Bundle via onSaveInstanceState, qui survit à la fois à App Freezer et à Process Death. Contrairement à iOS, où le déchargement de Suspended est une situation exceptionnelle, sous Android Process Death est un comportement normal qui doit toujours être attendu.

kotlin
// SavedStateHandle — salut de Process Death sur Android
class CheckoutViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    // État qui survit au processus même après App Freezer
    var currentStep: MutableLiveData<Int> =
        savedStateHandle.getLiveData("checkout_step", 1)

    var cartItems: MutableLiveData<List<CartItem>> =
        savedStateHandle.getLiveData("cart_items", emptyList())

    fun proceedToNextStep() {
        currentStep.value = (currentStep.value ?: 0) + 1
    }

    fun addToCart(item: CartItem) {
        val updatedList = (cartItems.value ?: emptyList()) + item
        cartItems.value = updatedList
        savedStateHandle["cart_items"] = updatedList
    }
}

// Sauvegarder dans onStop en cas d'App Freezer
class MainActivity : AppCompatActivity() {

    override fun onStop() {
        super.onStop()
        // Sauvegarder les données qui doivent survivre au gel
        saveDraftData()
        // Libérer les ressources inutiles dans un état gelé
        releaseHeavyResources()
        // Avertir que l'application va être gelée
        // (Journalisation pour débogage)
        Log.d("Lifecycle", "Activity stopped — possible App Freeze")
    }
}

Le code montre l'approche pour gérer l'analogue de Suspended sous Android. SavedStateHandle dans ViewModel sauvegarde et restaure automatiquement les données lors de Process Death. onStop est le dernier événement garantie avant un possible App Freezer ou une terminaison de processus. L'état du formulaire de paiement, la liste des articles dans le panier — toutes ces données survivent au gel grâce à SavedStateHandle. Pour les ressources lourdes (bitmaps, curseurs de base de données), onStop est l'endroit pour libérer la mémoire.

State Restoration : récupération après Suspended

State Restoration est un mécanisme intégré d'iOS pour sauvegarder et restaurer l'état de l'interface utilisateur après que l'application a été déchargée de la mémoire. Si l'application était en Suspended et que le système l'a déchargée, au prochain démarrage à froid, state restoration restaure la pile de navigation, la position de défilement, l'état du formulaire et d'autres éléments d'UI. L'utilisateur revient au même écran où il s'était arrêté.

State Restoration fonctionne via les protocoles UIViewControllerRestoration et UIStateRestoring. Le développeur attribue un restorationIdentifier à chaque ViewController et View qu'il souhaite restaurer. En allant en arrière-plan, iOS encode l'état de ces objets. Au retour après un déchargement, iOS crée de nouveaux objets et décode l'état sauvegardé. Sans state restoration, l'utilisateur verra un écran vide après un démarrage à froid au lieu de l'endroit où il s'était arrêté.

swift
import UIKit

class DetailViewController: UIViewController {

    var itemID: String = ""
    var scrollPosition: CGPoint = .zero

    override func viewDidLoad() {
        super.viewDidLoad()
        restorationIdentifier = "DetailViewController"
        restorationClass = type(of: self)
    }

    override func encodeRestorableState(with coder: NSCoder) {
        super.encodeRestorableState(with: coder)
        coder.encode(itemID, forKey: "itemID")
        coder.encode(scrollPosition, forKey: "scrollPosition")
    }

    override func decodeRestorableState(with coder: NSCoder) {
        super.decodeRestorableState(with: coder)
        if let savedID = coder.decodeObject(forKey: "itemID") as? String {
            itemID = savedID
            loadItem()
        }
        if let savedPosition = coder.decodeCGPoint(forKey: "scrollPosition") {
            scrollPosition = savedPosition
            // Restaurer la position après le chargement des données
        }
    }
}

// AppDelegate — activation de State Restoration
func application(
    _ application: UIApplication,
    shouldSaveSecureApplicationState coder: NSCoder
) -> Bool {
    return true
}

func application(
    _ application: UIApplication,
    shouldRestoreSecureApplicationState coder: NSCoder
) -> Bool {
    return true
}

Le code montre l'implémentation de State Restoration sur iOS. restorationIdentifier et restorationClass sont nécessaires pour chaque ViewController restaurable. encodeRestorableState/decodeRestorableState sauvegardent et chargent les données via NSCoder. Dans AppDelegate, shouldSaveSecureApplicationState et shouldRestoreSecureApplicationState activent la sauvegarde chiffrée de l'état. Sous iOS 12+, il est recommandé d'utiliser le codage sécurisé (NSSecureCoding) pour la protection des données.

Meilleures pratiques pour travailler avec Suspended

La première règle — ne supposez jamais que l'application reviendra de Suspended. Le système peut décharger l'application à tout moment. Toutes les données cruciales doivent être sauvegardées dans un stockage persistant avant la transition vers Suspended — c'est-à-dire dans applicationDidEnterBackground ou onStop. UserDefaults, Core Data, File Manager — des options de stockage appropriées. La mémoire (variables, propriétés) est un stockage peu fiable pour les données qui doivent survivre à Suspended.

La deuxième règle — libérez les ressources avant Suspended. Fermez les descripteurs de fichier, libérez la mémoire GPU (Metal, Core Graphics), fermez les connexions réseau. Bien que l'application ne consomme pas de CPU dans Suspended, les ressources occupées sont bloquées pour les autres applications. Sur iOS, les sockets ne peuvent pas rester ouverts dans Suspended — au retour de Suspended, ils peuvent ne pas être fonctionnels, provoquant des erreurs.

La troisième règle — ne placez pas de logique dépendante du temps en attendant un retour de Suspended. Les minuteries, callbacks et l'activité réseau cessent dans Suspended. Si l'application est restée en Suspended pendant plusieurs heures, une minuterie peut se déclencher incorrectement au retour. Vérifiez la validité des données au retour — le cache peut être obsolète et le jeton d'autorisation peut avoir expiré.

La quatrième règle — utilisez State Restoration pour tous les écrans, en particulier les formulaires de saisie, les listes défilables et les écrans de détail. Sans state restoration, après être revenu d'un Suspended déchargé, l'utilisateur verra l'écran initial de l'application au lieu de l'endroit où il s'était arrêté. Cela dégrade l'expérience utilisateur et force l'utilisateur à répéter des actions.

swift
import UIKit

// Vérification : l'application a-t-elle été déchargée de la mémoire ?
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    // Vérifier si un état sauvegardé existe
    if UserDefaults.standard.object(forKey: "navStack") != nil {
        // L'application a été déchargée de Suspended
        // Doit restaurer l'état
        restoreNavigationStack()
    } else {
        // Démarrage à froid propre depuis Not Running
        showOnboardingIfNeeded()
    }
    return true
}

private func restoreNavigationStack() {
    guard let savedStack = UserDefaults.standard.array(forKey: "navStack") as? [String],
          let navController = window?.rootViewController as? UINavigationController
    else { return }

    for vcClassName in savedStack {
        if let vcClass = NSClassFromString(vcClassName) as? UIViewController.Type {
            let vc = vcClass.init()
            navController.pushViewController(vc, animated: false)
        }
    }
}

Le code montre la pratique pour déterminer si l'application a été déchargée de Suspended. Vérifier UserDefaults pour la présence d'une pile de navigation sauvegardée permet de distinguer un démarrage à froid après déchargement d'un démarrage à froid propre. Dans le premier cas, la pile de navigation est restaurée ; dans le second, l'écran d'onboarding ou principal est affiché. Cette approche complète State Restoration intégré pour les cas où NSCoder est insuffisant.

Foire aux questions

Combien de temps une application peut-elle rester en Suspended ?

Illimité — de quelques secondes à plusieurs jours. iOS n'a pas de délai pour Suspended. L'application restera en mémoire jusqu'à ce que le système décide de la décharger par manque de ressources. Dans la pratique, les applications restent en Suspended de 15 minutes à plusieurs heures, selon la RAM de l'appareil et le nombre d'applications actives.

Est-ce que applicationWillTerminate est appelé lors du déchargement de Suspended ?

Non. applicationWillTerminate n'est pas appelé lorsque l'application est déchargée de Suspended. Le système libère simplement la mémoire sans avertir l'application. C'est une raison supplémentaire pour laquelle toute sauvegarde de données doit se produire dans applicationDidEnterBackground. applicationWillTerminate n'est appelé que lorsque l'utilisateur termine manuellement l'application en la glissant hors de l'App Switcher.

Android a-t-il un analogue de Suspended ?

Il n'existe pas d'analogue direct. Sous Android 11+, App Freezer a été introduit, qui suspend les processus en arrière-plan via SIGSTOP — c'est fonctionnellement similaire à Suspended. Cependant, les applications Android doivent être conçues en supposant Process Death à tout moment. Utilisez SavedStateHandle dans ViewModel et onSaveInstanceState pour sauvegarder l'état qui survivra à la fois à App Freezer et à Process Death.

Comment vérifier si l'application était en Suspended ?

Dans iOS, il n'y a pas d'API directe pour vérifier. Une méthode indirecte : vérifier UserDefaults pour la présence d'un état sauvegardé dans didFinishLaunchingWithOptions. Si l'état existe — l'application a été déchargée de Suspended et démarre à froid. Si l'état n'existe pas — c'est un démarrage à froid propre. Dans SwiftUI, on peut sauvegarder un indicateur dans scenePhase.background et le vérifier au prochain lancement.

Qu'est-ce qu'un snapshot dans le contexte de Suspended ?

Lors de la transition vers Suspended, iOS prend un snapshot — une capture d'écran de l'interface actuelle de l'application. Cette capture est affichée dans l'App Switcher et lors du retour à l'application (comme une animation de « décongélation »). Si l'application contient des données confidentielles, le snapshot peut les exposer. Pour vous protéger, utilisez UIApplication.shouldSnapshotSecureApp (iOS 16+) ou appliquez une superposition de flou dans applicationDidEnterBackground.

Résumé

  • Suspended — l'application est gelée dans la mémoire iOS, le code n'est pas exécuté, mais la pile d'UI est préservée pour une restauration instantanée
  • Caractère unique d'iOS — Suspended n'existe pas dans Android ; Android utilise App Freezer (SIGSTOP) comme analogue partiel
  • Déchargement — le système décharge les applications Suspended en priorité lorsque la mémoire est faible, sans notification
  • Sauvegarde — applicationDidEnterBackground est la dernière méthode garantie ; toutes les données doivent être sauvegardées ici
  • State Restoration — mécanisme basé sur NSCoder pour la restauration automatique de l'UI après le déchargement de Suspended
  • Alternative Android — SavedStateHandle + onSaveInstanceState pour survivre à Process Death
  • Snapshot — iOS prend une capture d'écran pendant Suspended ; les données confidentielles doivent être masquées via une superposition de flou ou un snapshot sécurisé

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi