Suspended — ce este, înghețarea aplicației în fundal iOS

Autor: IT Sectr Publicat: 2026-03-03 Timp de citire: 11 min

Suspended — stare suspendată a ciclului de viață al aplicației iOS, în care aceasta este înghețată în memorie, dar nu execută cod. Arătăm cum funcționează Suspended, ce riscuri implică înghețarea aplicației în fundal, cum gestionează iOS descărcarea aplicațiilor în Suspended și cum să implementăm state restoration pentru restaurarea fără probleme după revenirea din Suspended.

Puncte principale

  • Suspended — aplicația este înghețată în memorie, codul nu se execută, stiva UI este păstrată
  • iOS Suspended — stare unică, inexistentă în Android; procesul există, dar nu este activ
  • Descărcarea — la lipsa de memorie, aplicațiile Suspended sunt șterse primele, datele din memorie se pierd
  • State Restoration — mecanism iOS pentru salvarea și restaurarea stivei UI după descărcare
  • didEnterBackground — ultima metodă garantată a fi apelată înainte de Suspended

Suspended — ce fel de stare este

Suspended — starea ciclului de viață al aplicației iOS în care aceasta se află în memoria operativă a dispozitivului, dar nu execută niciun cod. Este starea finală înainte de terminarea completă: aplicația trece în Suspended din Background după finalizarea tuturor sarcinilor de fundal sau după expirarea timpului de așteptare. În Suspended aplicația este complet înghețată — toate threadurile sunt suspendate, timer-ele nu funcționează, activitatea de rețea lipsește.

Suspended — o caracteristică unică iOS, inexistentă în ciclul de viață standard al Android. Motivul este arhitectura diferită a gestionării proceselor. iOS păstrează imaginea aplicației în memorie (analog hibernării pe desktop) pentru ca la revenirea utilizatorului să restaureze instantaneu interfața fără cold start. Android nu are Suspended — procesul fie există și poate executa cod (Background), fie este terminat (Not Running), deși Android poate suspenda executarea threadurilor prin LMK.

Pentru utilizator Suspended apare ca o restaurare instantanee: el comută între aplicații prin App Switcher și fiecare aplicație se deschide de unde a lăsat-o. Aceasta creează iluzia că toate aplicațiile rulează simultan. În realitate, majoritatea sunt înghețate în Suspended. Hot start din Suspended este de multe ori mai rapid decât cold start din Not Running, deoarece codul este deja încărcat în memorie.

Cum gestionează sistemul Suspended

iOS monitorizează starea tuturor aplicațiilor și ia decizia de descărcare a aplicațiilor Suspended pe baza memoriei disponibile. Când memoria este insuficientă, sistemul începe să descarce aplicațiile Suspended, începând cu cele care se află cel mai mult timp în această stare. Dacă memoria este încă insuficientă, sistemul mută aplicațiile din Background și Inactive în Suspended, apoi le descarcă. Acest proces este complet transparent pentru utilizator — el vede doar pictograma aplicației în App Switcher, care la click pornește un cold start.

CaracteristicăSuspended (iOS)Background (iOS)Background (Android)
Se execută codNuDa (limitat)Da (limitat)
În memorieDaDaDa
Consum CPU0%ScăzutScăzut
Hot startDa — restaurare instantaneeDa — prin InactiveNu — procesul poate fi fost ucis
TimeoutNu — poate sta în memorie ore întregi~30 secunde (după beginBackgroundTask)Depinde de versiunea API
Descărcare de sistemLa lipsa de memorieLa lipsa critică de memorieLMK (Low Memory Killer)
Revenirea la lucruDin App Switcher — instantaneuDin App Switcher — prin InactiveCold start
State RestorationRecomandatNu este necesarSavedStateHandle

Suspended în iOS: mecanismul de înghețare

În iOS Suspended este atins automat după finalizarea tuturor sarcinilor de fundal. Sistemul apelează applicationDidEnterBackground, oferă timp pentru executarea beginBackgroundTask (aproximativ 30 de secunde), după care suspendă forțat toate threadurile și mută aplicația în starea Suspended. Obiectele din memorie sunt păstrate, dar niciun cod nu se execută — aplicația este înghețată în starea curentă.

Moment critic: applicationDidEnterBackground — ultima metodă garantată a fi apelată înainte de Suspended. După aceasta, aplicația nu primește nicio notificare despre descărcarea din memorie. Dacă utilizatorul sau sistemul ucide aplicația aflată în Suspended, nu se apelează nici applicationWillTerminate, nici din nou applicationDidEnterBackground. Prin urmare, toată salvarea datelor trebuie să aibă loc în applicationDidEnterBackground, nu în applicationWillTerminate.

swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // Ultimul apel garantat înainte de Suspended
    func applicationDidEnterBackground(_ application: UIApplication) {
        // Salvăm tot ce trebuie să supraviețuiască descărcării din memorie
        savePersistentState()
        saveNavigationStack()

        // Solicităm timp suplimentar dacă este necesar
        let task = application.beginBackgroundTask {
            application.endBackgroundTask(task)
        }
    }

    // Revenirea din Suspended — hot start
    func applicationWillEnterForeground(_ application: UIApplication) {
        // Aplicația era în Suspended, revenim la lucru
        print("Revenirea din Suspended sau Background")
    }

    // Restaurare completă după descărcarea din memorie
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Dacă este cold start după descărcarea din Suspended —
        // restaurăm state restoration
        return true
    }

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

    private func saveNavigationStack() {
        guard let rootVC = window?.rootViewController else { return }
        // Salvăm stiva curentă de navigare
        if let navController = rootVC as? UINavigationController {
            let vcClasses = navController.viewControllers.map { type(of: $0) }
            UserDefaults.standard.set(vcClasses.map { NSStringFromClass($0) }, forKey: "navStack")
        }
    }
}

Codul arată gestionarea critică a Suspended pe iOS. applicationDidEnterBackground — ultimul apel garantat. Toate salvările de date trebuie să aibă loc aici: starea utilizatorului, stiva de navigare, ciorne, timer-e. applicationWillEnterForeground este apelat la revenirea din Suspended sau Background. didFinishLaunchingWithOptions — doar la cold start, când aplicația a fost descărcată din memorie după Suspended.

Suspended în Android — există un analog

În Android nu există un analog direct al iOS Suspended. Android nu îngheață aplicațiile în memorie cu păstrarea contextului de execuție. În schimb, Android fie menține procesul în fundal (Background), fie îl termină (Not Running). Totuși, pe Android 11+ (API 30) a apărut mecanismul App Freezer, care suspendă executarea proceselor de fundal cu ajutorul semnalului SIGSTOP. Acesta este un analog funcțional al Suspended, dar cu diferențe importante.

App Freezer — parte a sistemului de gestionare a memoriei Android. Când aplicația stă mult timp în fundal și nu are notificări active, sistemul îi trimite SIGSTOP, suspendând toate threadurile. La revenirea aplicației în prim-plan, se trimite SIGCONT și executarea este reluată. Diferența cheie față de iOS: App Freezer nu garantează păstrarea stării — datele din memorie pot fi pierdute dacă procesul este ucis în timpul înghețării.

Pe Android se recomandă utilizarea SavedStateHandle în ViewModel pentru salvarea automată a stării la orice terminare a procesului. SavedStateHandle salvează datele în Bundle prin onSaveInstanceState, care supraviețuiește atât App Freezer, cât și Process Death. Spre deosebire de iOS, unde descărcarea din Suspended este o situație excepțională, pe Android Process Death este un comportament normal care trebuie așteptat întotdeauna.

kotlin
// SavedStateHandle — salvare de la Process Death pe Android
class CheckoutViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    // Stare care supraviețuiește procesului chiar și după 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
    }
}

// Salvare în onStop în caz de App Freezer
class MainActivity : AppCompatActivity() {

    override fun onStop() {
        super.onStop()
        // Salvăm datele care trebuie să supraviețuiască înghețării
        saveDraftData()
        // Eliberăm resursele care nu sunt necesare în stare înghețată
        releaseHeavyResources()
        // Avertizăm că aplicația va fi înghețată
        // (Logare pentru depanare)
        Log.d("Lifecycle", "Activity oprită — posibil App Freeze")
    }
}

Codul arată abordarea de gestionare a analogului Suspended pe Android. SavedStateHandle în ViewModel salvează și restaurează automat datele la Process Death. onStop — ultimul eveniment garantat înainte de posibilul App Freezer sau terminarea procesului. Starea formularului de comandă, lista produselor din coș — toate aceste date supraviețuiesc înghețării datorită SavedStateHandle. Pentru resurse grele (bitmap-uri, cursorii de baze de date) onStop este locul pentru eliberarea memoriei.

State Restoration: restaurarea după Suspended

State Restoration — mecanismul încorporat iOS pentru salvarea și restaurarea stării UI după descărcarea aplicației din memorie. Dacă aplicația era în Suspended și sistemul a descărcat-o, la următorul cold start state restoration restaurează stiva de navigare, poziția de scroll, starea formularelor și alte elemente UI. Utilizatorul revine la aceeași ecran unde s-a oprit.

State Restoration funcționează prin protocoalele UIViewControllerRestoration și UIStateRestoring. Dezvoltatorul atribuie restorationIdentifier fiecărui ViewController și View pe care dorește să le restaureze. La trecerea în Background, iOS codifică starea acestor obiecte. După revenirea din descărcare, iOS creează obiecte noi și decodează starea salvată. Fără state restoration utilizatorul va vedea un ecran gol după cold start în locul locului unde s-a oprit.

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
            // Restaurăm poziția după încărcarea datelor
        }
    }
}

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

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

Codul arată implementarea State Restoration pe iOS. restorationIdentifier și restorationClass sunt necesare pentru fiecare ViewController care trebuie restaurat. encodeRestorableState/decodeRestorableState salvează și încarcă datele prin NSCoder. În AppDelegate, shouldSaveSecureApplicationState și shouldRestoreSecureApplicationState activează salvarea criptată a stării. De la iOS 12+ se recomandă utilizarea secure encoding (NSSecureCoding) pentru protejarea datelor.

Cele mai bune practici de lucru cu Suspended

Prima regulă — nu presupuneți niciodată că aplicația va reveni din Suspended. Sistemul poate descărca aplicația în orice moment. Toate datele critic de importante trebuie salvate în stocare persistentă înainte de trecerea în Suspended — adică în applicationDidEnterBackground sau onStop. UserDefaults, Core Data, File Manager — depozite adecvate. Memoria (variabile, proprietăți) — un depozit nesigur pentru datele care trebuie să supraviețuiască Suspended.

A doua regulă — eliberați resursele înainte de Suspended. Închideți descriptori de fișiere, eliberați memoria GPU (Metal, Core Graphics), închideți conexiunile de rețea. Deși aplicația nu consumă CPU în Suspended, resursele ocupate sunt blocate pentru alte aplicații. Pe iOS în Suspended nu se pot menține socket-uri deschise — la revenirea din Suspended acestea pot fi nefuncționale, ceea ce va cauza erori.

A treia regulă — nu plasați logică dependentă de timp în așteptarea revenirii din Suspended. Timer-ele, callback-urile și activitatea de rețea se opresc în Suspended. Dacă aplicația a fost în Suspended câteva ore, la revenire timer-ul poate acționa incorect. Verificați actualitatea datelor la revenire — poate cache-ul este învechit, iar token-ul de autentificare a expirat.

A patra regulă — utilizați State Restoration pentru toate ecranele, în special pentru formulare de introducere, liste cu derulare și ecrane de detaliu. Fără state restoration, utilizatorul după revenirea din Suspended descărcat va vedea ecranul inițial al aplicației în locul locului unde s-a oprit. Acest lucru degradează experiența utilizatorului și îl obligă să repete acțiunile.

swift
import UIKit

// Verificare: a fost aplicația descărcată din memorie?
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    // Verificăm dacă există stare salvată
    if UserDefaults.standard.object(forKey: "navStack") != nil {
        // Aplicația a fost descărcată din Suspended
        // Trebuie restaurată starea
        restoreNavigationStack()
    } else {
        // Cold start curat din 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)
        }
    }
}

Codul arată practica de determinare dacă aplicația a fost descărcată din Suspended. Verificarea UserDefaults pentru existența stivei de navigare salvată permite diferențierea cold start-ului după descărcare de cold start-ul curat. În primul caz, stiva de navigare este restaurată, în al doilea — se afișează onboarding-ul sau ecranul principal. Această abordare completează State Restoration încorporat pentru cazurile în care NSCoder nu este suficient.

Întrebări frecvente

Cât timp poate rămâne o aplicație în Suspended?

Nelimitat — de la câteva secunde la câteva zile. iOS nu are un timeout pentru Suspended. Aplicația va rămâne în memorie până când sistemul decide să o descarce din cauza lipsei de resurse. În practică aplicațiile rămân în Suspended de la 15 minute la câteva ore, în funcție de cantitatea de RAM a dispozitivului și numărul de aplicații active.

Se apelează applicationWillTerminate la descărcarea din Suspended?

Nu. applicationWillTerminate nu este apelat la descărcarea aplicației din Suspended. Sistemul pur și simplu eliberează memoria fără notificarea aplicației. Acesta este încă un motiv pentru care toate salvările de date trebuie să aibă loc în applicationDidEnterBackground. applicationWillTerminate este apelat doar atunci când utilizatorul închide manual aplicația prin glisare din App Switcher.

Android are un analog al Suspended?

Nu există un analog direct. Pe Android 11+ a apărut App Freezer, care suspendă procesele de fundal prin SIGSTOP — este funcțional similar cu Suspended. Totuși, aplicațiile Android trebuie proiectate având în vedere Process Death în orice moment. Utilizați SavedStateHandle în ViewModel și onSaveInstanceState pentru salvarea stării care va supraviețui atât App Freezer, cât și Process Death.

Cum verific dacă aplicația a fost în Suspended?

În iOS nu există un API direct pentru verificare. Metoda indirectă: verificați UserDefaults pentru existența stării salvate în didFinishLaunchingWithOptions. Dacă starea există — aplicația a fost descărcată din Suspended și pornește la rece. Dacă starea nu există — cold start curat. În SwiftUI puteți salva un flag în scenePhase.background și verifica la următoarea pornire.

Ce este snapshot în contextul Suspended?

La trecerea în Suspended, iOS face un snapshot — o captură de ecran a UI-ului curent al aplicației. Această captură este afișată în App Switcher și la revenirea în aplicație (ca animație de «dezghețare»). Dacă aplicația conține date confidențiale, snapshot le poate dezvălui. Pentru protecție utilizați UIApplication.shouldSnapshotSecureApp (iOS 16+) sau aplicați un blur-overlay în applicationDidEnterBackground.

Rezumat

  • Suspended — aplicația este înghețată în memoria iOS, codul nu se execută, dar stiva UI este păstrată pentru restaurare instantanee
  • Unicitatea iOS — Suspended nu există în Android; Android folosește App Freezer (SIGSTOP) ca analog parțial
  • Descărcarea — sistemul descarcă aplicațiile Suspended cu prioritate maximă la lipsa de memorie, fără notificare
  • Salvarea — applicationDidEnterBackground — ultima metodă garantată, toate datele trebuie salvate aici
  • State Restoration — mecanism NSCoder pentru restaurarea automată a UI după descărcarea din Suspended
  • Alternativa Android — SavedStateHandle + onSaveInstanceState pentru supraviețuirea Process Death
  • Snapshot — iOS face o captură de ecran la Suspended; datele confidențiale trebuie ascunse prin blur-overlay sau secure snapshot

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și