Suspended — co to je, zmrazení aplikace na pozadí iOS

Autor: IT Sectr Publikováno: 2026-03-03 Doba čtení: 11 min

Suspended — pozastavený stav životního cyklu iOS aplikace, ve kterém je zmrazena v paměti, ale nevykonává kód. Ukazujeme, jak Suspended funguje, jaká rizika přináší zmrazení aplikace na pozadí, jak iOS spravuje vykládku aplikací v Suspended a jak implementovat state restoration pro bezproblémové obnovení po návratu z Suspended.

Hlavní body

  • Suspended — aplikace je zmrazena v paměti, kód se nevykonává, zásobník UI je zachován
  • iOS Suspended — jedinečný stav, který v Androidu neexistuje; proces existuje, ale není aktivní
  • Vykládka — při nedostatku paměti jsou aplikace v Suspended odstraněny jako první, data v paměti se ztrácejí
  • State Restoration — mechanismus iOS pro ukládání a obnovení zásobníku UI po vykládce
  • didEnterBackground — poslední metoda, která je zaručeně volána před Suspended

Suspended — co je to za stav

Suspended — stav životního cyklu iOS aplikace, ve kterém se nachází v operační paměti zařízení, ale nevykonává žádný kód. Jedná se o konečný stav před úplným ukončením: aplikace přechází do Suspended z Background po dokončení všech úkolů na pozadí nebo po uplynutí časového limitu. V Suspended je aplikace zcela zmrazena — všechna vlákna jsou pozastavena, časovače nefungují, síťová aktivita není přítomna.

Suspended — jedinečná vlastnost iOS, která neexistuje ve standardním životním cyklu Androidu. Důvodem je odlišná architektura řízení procesů. iOS uchovává obraz aplikace v paměti (analogie hibernace na desktopu), aby při návratu uživatele okamžitě obnovil rozhraní bez cold startu. Android nemá Suspended — proces buď existuje a může vykonávat kód (Background), nebo je ukončen (Not Running), i když Android může pozastavit provádění vláken prostřednictvím LMK.

Pro uživatele vypadá Suspended jako okamžité obnovení: přepíná mezi aplikacemi pomocí App Switcher a každá aplikace se otevírá na stejném místě, kde ji nechal. To vytváří iluzi, že všechny aplikace běží současně. Ve skutečnosti je většina z nich zmrazena v Suspended. Hot start z Suspended je nđ2ikrát rychlejší než cold start z Not Running, protože kód je již načten v paměti.

Jak systém spravuje Suspended

iOS sleduje stav všech aplikací a rozhoduje o vykládce aplikací v Suspended na základě dostupné paměti. Když paměť nestačí, systém začíná vykládět aplikace v Suspended, počínaje těmi, které jsou v tomto stavu nejdéle. Pokud paměť stále nestačí, systém přesouá aplikace z Background a Inactive do Suspended a následně je vykládá. Tento proces je pro uživatele zcela transparentní — vidí pouze ikonu aplikace v App Switcher, která při kliknutí spouští cold start.

VlastnostSuspended (iOS)Background (iOS)Background (Android)
Kód se vykonáváNeAno (omezeně)Ano (omezeně)
V pamětiAnoAnoAno
Spotřeba CPU0%NízkáNízká
Hot startAno — okamžité obnoveníAno — přes InactiveNe — proces mohl být zabit
Časový limitNe — může být v paměti hodiny~30 sekund (po beginBackgroundTask)Závisí na verzi API
Vykládka systémemPři nedostatku pamětiPři kritickém nedostatku pamětiLMK (Low Memory Killer)
Návrat k práciZ App Switcher — okamžitěZ App Switcher — přes InactiveCold start
State RestorationDoporučuje seNení vyžadovánSavedStateHandle

Suspended v iOS: mechanismus zmrazení

V iOS je Suspended dosaženo automaticky po dokončení všech úkolů na pozadí. Systém zavolá applicationDidEnterBackground, dá čas na provedení beginBackgroundTask (přibližně 30 sekund), poté núze pozastaví všechna vlákna a přesune aplikaci do stavu Suspended. Objekty v paměti jsou zachovány, ale žádný kód se nevykonává — aplikace je zmrazena v aktuálním stavu.

Kriticky důležitý okamžik: applicationDidEnterBackground — poslední metoda, která je zaručeně volána před Suspended. Poté aplikace nepřijímá žádná oznámení o vykládce z paměti. Pokud uživatel nebo systém zabije aplikaci nacházející se v Suspended, není voláno ani applicationWillTerminate, ani znovu applicationDidEnterBackground. Proto veškeré ukládání dat musí probíhat v applicationDidEnterBackground, nikoli v applicationWillTerminate.

swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // Poslední zaručený hovor před Suspended
    func applicationDidEnterBackground(_ application: UIApplication) {
        // Ukládáme vše, co má přežít vykládku z paměti
        savePersistentState()
        saveNavigationStack()

        // Žádáme o další čas, pokud je to nutné
        let task = application.beginBackgroundTask {
            application.endBackgroundTask(task)
        }
    }

    // Návrat z Suspended — hot start
    func applicationWillEnterForeground(_ application: UIApplication) {
        // Aplikace byla v Suspended, vracíme se k práci
        print("Návrat z Suspended nebo Background")
    }

    // Úplné obnovení po vykládce z paměti
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Pokud se jedná o cold start po vykládce z Suspended —
        // obnovujeme state restoration
        return true
    }

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

    private func saveNavigationStack() {
        guard let rootVC = window?.rootViewController else { return }
        // Ukládáme aktuální navigační zásobník
        if let navController = rootVC as? UINavigationController {
            let vcClasses = navController.viewControllers.map { type(of: $0) }
            UserDefaults.standard.set(vcClasses.map { NSStringFromClass($0) }, forKey: "navStack")
        }
    }
}

Kód ukazuje kritické zpracování Suspended v iOS. applicationDidEnterBackground — poslední zaručený hovor. Všechna uložení dat by měla probíhat zde: stav uživatele, navigační zásobník, koncepty, časovače. applicationWillEnterForeground je volána při návratu z Suspended nebo Background. didFinishLaunchingWithOptions — pouze při cold startu, když byla aplikace vykládena z paměti po Suspended.

Suspended v Androidu — existuje analogie

V Androidu neexistuje přímá analogie iOS Suspended. Android nezmrazuje aplikace v paměti s uchováním kontextu provádění. Místo toho Android buď drží proces na pozadí (Background), nebo jej ukončuje (Not Running). Nicméně na Android 11+ (API 30) se objevil mechanismus App Freezer, který pozastavuje provádění procesů na pozadí pomocí signálu SIGSTOP. Jedná se o funkční analogii Suspended, ale s důležitými rozdíly.

App Freezer — část systému řízení paměti Androidu. Když je aplikace dlouho na pozadí a nemá žádná aktivní oznámení, systém jí pošle SIGSTOP, čímž pozastaví všechna vlákna. Při návratu aplikace na popředí je odeslán SIGCONT a provádění je obnoveno. Klíčový rozdíl oproti iOS: App Freezer nezaručuje zachování stavu — data v paměti mohou být ztracena, pokud je proces během zmrazení zabit.

Na Androidu se doporučuje používání SavedStateHandle ve ViewModel pro automatické ukládání stavu při jakémkoli ukončení procesu. SavedStateHandle ukládá data do Bundle prostřednictvím onSaveInstanceState, který přežije jak App Freezer, tak Process Death. Na rozdíl od iOS, kde je vykládka z Suspended výjimečná situace, v Androidu je Process Death normální chování, které by mělo být vždy očekáváno.

kotlin
// SavedStateHandle — záchrana před Process Death na Androidu
class CheckoutViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    // Stav, který přežije proces i po 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
    }
}

// Ukládání v onStop pro případ App Freezer
class MainActivity : AppCompatActivity() {

    override fun onStop() {
        super.onStop()
        // Ukládáme data, která mají přežít zmrazení
        saveDraftData()
        // Uvolňujeme zdroje, které nejsou potřeba ve zmrazeném stavu
        releaseHeavyResources()
        // Varujeme, že aplikace bude zmrazena
        // (Logování pro ladění)
        Log.d("Lifecycle", "Activity zastavena — možné App Freeze")
    }
}

Kód ukazuje přístup ke zpracování analogie Suspended na Androidu. SavedStateHandle ve ViewModel automaticky ukládá a obnovuje data při Process Death. onStop — poslední zaručená událost před možným App Freezerem nebo ukončením procesu. Stav objednávkového formuláře, seznam produktů v košíku — všechna tato data přežijí zmrazení díky SavedStateHandle. Pro těžké zdroje (bitmapy, kurzory databáze) je onStop místem pro uvolnění paměti.

State Restoration: obnovení po Suspended

State Restoration — vestavěný mechanismus iOS pro ukládání a obnovení stavu UI po vykládce aplikace z paměti. Pokud byla aplikace v Suspended a systém ji vykládl, při následujícím cold startu state restoration obnoví navigační zásobník, pozici posouvání, stav formulářů a další prvky UI. Uživatel se vrací na stejnou obrazovku, kde se zastavil.

State Restoration funguje prostřednictvím protokolů UIViewControllerRestoration a UIStateRestoring. Vývojář přiřazuje restorationIdentifier každému ViewController a View, které chce obnovit. Při přechodu do Background iOS kóduje stav těchto objektů. Po návratu z vykládky iOS vytváří nové objekty a dekóduje uložený stav. Bez state restoration uživatel uvidí prázdnou obrazovku po cold startu místo místa, kde se zastavil.

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
            // Obnovujeme pozici po načtení dat
        }
    }
}

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

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

Kód ukazuje implementaci State Restoration v iOS. restorationIdentifier a restorationClass jsou nezbytné pro každý obnovovaný ViewController. encodeRestorableState/decodeRestorableState ukládají a načítají data prostřednictvím NSCoder. V AppDelegate, shouldSaveSecureApplicationState a shouldRestoreSecureApplicationState zapínají šifrované ukládání stavu. Od iOS 12+ se doporučuje používání secure encoding (NSSecureCoding) pro ochranu dat.

Nejlepší postupy práce se Suspended

První pravidlo — nikdy nepředpokládejte, že se aplikace vrátí z Suspended. Systém může aplikaci kdykoli vykládt. Všechna kriticky důležitá data musí být uložena v trvalém úložišti před přechodem do Suspended — tj. v applicationDidEnterBackground nebo onStop. UserDefaults, Core Data, File Manager — vhodná úložiště. Paměť (proměnné, vlastnosti) — nespolehlivé úložiště pro data, která mají přežít Suspended.

Druhé pravidlo — uvolňujte zdroje před Suspended. Zavírejte deskriptory souborů, uvolňujte paměť GPU (Metal, Core Graphics), zavírejte síťová připojení. I když aplikace nespotřebovává CPU v Suspended, obsazené zdroje jsou blokovány pro jiné aplikace. V iOS v Suspended nelze držet otevřené sockety — při návratu z Suspended mohou být nefunkční, což způsobí chyby.

Třetí pravidlo — neumisťujte logiku závislou na čase v očekávání návratu z Suspended. Časovače, callbacky a síťová aktivita se v Suspended zastavují. Pokud byla aplikace v Suspended několik hodin, při návratu může časovač fungovat nesprávně. Kontrolujte aktuálnost dat při návratu — možná je cache zastaralá a autorizační token vypršel.

Čtvrté pravidlo — používejte State Restoration pro všechny obrazovky, zejména pro vstupní formuláře, seznamy s posouváním a detailní obrazovky. Bez state restoration uživatel po návratu z vykládeného Suspended uvidí počáteční obrazovku aplikace místo místa, kde se zastavil. To zhoršuje uživatelský zážitek a nutí uživatele opakovat akce.

swift
import UIKit

// Kontrola: byla aplikace vykládena z paměti?
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    // Kontrolujeme, zda existuje uložený stav
    if UserDefaults.standard.object(forKey: "navStack") != nil {
        // Aplikace byla vykládena z Suspended
        // Je třeba obnovit stav
        restoreNavigationStack()
    } else {
        // Čistý cold start z 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)
        }
    }
}

Kód ukazuje praxi určení, zda byla aplikace vykládena z Suspended. Kontrola UserDefaults na přítomnost uloženého navigačního zásobníku umožňuje odlišit cold start po vykládce od čistého cold startu. V prvním případě se navigační zásobník obnoví, ve druhém — zobrazí se onboarding nebo hlavní obrazovka. Tento přístup doplňuje vestavěný State Restoration pro případy, kdy NSCoder nestačí.

Často kladené otázky

Jak dlouho může aplikace zůstat v Suspended?

Neomezeně — od několika sekund do několika dní. iOS nemá časový limit pro Suspended. Aplikace zůstane v paměti, dokud se systém nerozhodne ji vykládt kvůli nedostatku zdrojů. V praxi zůstávají aplikace v Suspended od 15 minut do několika hodin, v závislosti na množství RAM zařízení a počtu aktivních aplikací.

Je applicationWillTerminate voláno při vykládce z Suspended?

Ne. applicationWillTerminate není volána při vykládce aplikace z Suspended. Systém jednoduše uvolní paměť bez upozornění aplikace. To je další důvod, proč by veškeré ukládání dat mělo probíhat v applicationDidEnterBackground. applicationWillTerminate je volána pouze tehdy, když uživatel ručně ukončí aplikaci tažením z App Switcher.

Má Android analogii Suspended?

Přímá analogie neexistuje. Na Android 11+ se objevil App Freezer, který pozastavuje procesy na pozadí prostřednictvím SIGSTOP — je funkčně podobný Suspended. Nicméně aplikace pro Android by měly být navrhovány s očekáváním Process Death kdykoli. Používejte SavedStateHandle ve ViewModel a onSaveInstanceState pro ukládání stavu, který přežije jak App Freezer, tak Process Death.

Jak zkontrolovat, zda byla aplikace v Suspended?

V iOS neexistuje přímé API pro kontrolu. Nepřímá metoda: zkontrolujte UserDefaults na přítomnost uloženého stavu v didFinishLaunchingWithOptions. Pokud stav existuje — aplikace byla vykládena z Suspended a startuje studeně. Pokud stav neexistuje — čistý cold start. V SwiftUI můžete uložit flag do scenePhase.background a zkontrolovat jej při následujícím spuštění.

Co je snapshot v kontextu Suspended?

Při přechodu do Suspended iOS pořídí snapshot — snímek obrazovky aktuálního UI aplikace. Tento snímek se zobrazuje v App Switcher a při návratu do aplikace (jako animace rozmrazení). Pokud aplikace obsahuje důvěrné údaje, snapshot je může odhalit. Pro ochranu použijte UIApplication.shouldSnapshotSecureApp (iOS 16+) nebo aplikujte blur-overlay v applicationDidEnterBackground.

Shrnutí

  • Suspended — aplikace je zmrazena v paměti iOS, kód se nevykonává, ale zásobník UI je zachován pro okamžité obnovení
  • Jedinečnost iOS — Suspended v Androidu neexistuje; Android používá App Freezer (SIGSTOP) jako částečnou analogii
  • Vykládka — systém vykládá aplikace v Suspended jako první při nedostatku paměti bez upozornění
  • Ukládání — applicationDidEnterBackground — poslední zaručená metoda, všechna data musí být uložena zde
  • State Restoration — mechanismus NSCoder pro automatické obnovení UI po vykládce z Suspended
  • Alternativa Androidu — SavedStateHandle + onSaveInstanceState pro přežití Process Death
  • Snapshot — iOS pořídí snímek obrazovky při Suspended; důvěrné údaje je třeba skrýt pomocí blur-overlay nebo secure snapshot

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také