Suspended — iOS tətbiqinin həyat dövrünün dayandırılmış vəziyyəti, burada tətbiq yaddaşda dondurulub, lakin kod icra etmir. Suspended-in necə işlədiyini, tətbiqin fon dondurulmasının hansı riskləri daşıdığını, iOS-un Suspended tətbiqlərin boşaldılmasını necə idarə etdiyini və Suspended-dən qayıtdıqdan sonra problemsiz bərpa üçün state restoration-un necə həyata keçiriləcəyini göstəririk.
Əsas məqamlar
Suspended — iOS tətbiqinin həyat dövrünün elə bir vəziyyətidir ki, tətbiq cihazın operativ yaddaşında yerləşir, lakin heç bir kod icra etmir. Bu tam başa çatmadan əvvəlki son vəziyyətdir: tətbiq bütün fon tapşırıqlarını tamamladıqdan sonra və ya vaxt aşımı bitdikdə Background-dan Suspended-ə keçir. Suspended-də tətbiq tamamilə dondurulub — bütün axınlar dayandırılıb, taymerlər işləmir, şəbəkə aktivliyi yoxdur.
Suspended — Android-in standart həyat dövründə olmayan unikal iOS xüsusiyyətidir. Səbəb proses idarəetməsinin fərqli arxitekturasıdır. iOS tətbiqin şəklini yaddaşda saxlayır (desktopdakı hibridasiyaya bənzər), istifadəçi qayıtdıqda soyuq start olmadan interfeysi dərhal bərpa etmək üçün. Android-də Suspended yoxdur — proses ya mövcuddur və kod icra edə bilər (Background), ya da başa çatıb (Not Running), baxmayaraq ki, Android LMK vasitəsilə axınların icrasını dayandıra bilər.
İstifadəçi üçün Suspended ani bərpa kimi görünür: o, App Switcher vasitəsilə tətbiqlər arasında keçid edir və hər tətbiq onu tərk etdiyi yerdən açılır. Bu, bütün tətbiqlərin eyni anda işlədiyi illüziyasını yaradır. Əslində onların çoxu Suspended-də dondurulub. Suspended-dən isti start Not Running-dən soyuq startdan qat-qat sürətlidir, çünki kod artıq yaddaşa yüklənib.
iOS bütün tətbiqlərin vəziyyətini izləyir və mövcud yaddaş əsasında Suspended tətbiqlərin boşaldılması haqqında qərar qəbul edir. Yaddaş çatışmadıqda sistem Suspended tətbiqləri boşaltmağa başlayır, ən uzun müddət bu vəziyyətdə qalanlardan başlayaraq. Əgər yaddaş hələ də çatmırsa, sistem Background və Inactive-dən tətbiqləri Suspended-ə keçirir və sonra boşaldır. Bu proses istifadəçi üçün tamamilə şəffafdır — o, sadəcə App Switcher-də tətbiqin işarəsini görür, kliklədikdə isə soyuq start işə düşür.
| Xüsusiyyət | Suspended (iOS) | Background (iOS) | Background (Android) |
|---|---|---|---|
| Kod icra olunur | Xeyr | Bəli (məhdud) | Bəli (məhdud) |
| Yaddaşda | Bəli | Bəli | Bəli |
| CPU istehlakı | 0% | Aşağı | Aşağı |
| İsti start | Bəli — ani bərpa | Bəli — Inactive vasitəsilə | Xeyr — proses öldürülə bilər |
| Vaxt aşımı | Xeyr — saatlarla yaddaşda qala bilər | ~30 saniyə (beginBackgroundTask-dən sonra) | API versiyasından asılıdır |
| Sistem tərəfindən boşaltma | Yaddaş çatışmazlığında | Kritik yaddaş çatışmazlığında | LMK (Low Memory Killer) |
| İşə qayıtma | App Switcher-dən — dərhal | App Switcher-dən — Inactive vasitəsilə | Soyuq start |
| State Restoration | Arzuolunan | Tələb olunmur | SavedStateHandle |
iOS-da Suspended bütün fon tapşırıqları tamamlandıqdan sonra avtomatik əldə edilir. Sistem applicationDidEnterBackground-ı çağırır, beginBackgroundTask-ın icrası üçün vaxt verir (təxminən 30 saniyə), bundan sonra bütün axınları məcburi dayandırır və tətbiqi Suspended vəziyyətinə keçirir. Yaddaşdakı obyektlər qorunur, lakin heç bir kod icra olunmur — tətbiq cari vəziyyətdə dondurulur.
Kritik vacib məqam: applicationDidEnterBackground — Suspended-dən əvvəl zəmanətli çağırılan son metoddur. Bundan sonra tətbiq yaddaşdan boşaldılması haqqında heç bir bildiriş almır. Əgər istifadəçi və ya sistem Suspended vəziyyətində olan tətbiqi öldürürsə, nə applicationWillTerminate, nə də təkrar applicationDidEnterBackground çağırılır. Buna görə bütün məlumatların saxlanması applicationDidEnterBackground-da, applicationWillTerminate-də deyil, baş verməlidir.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Suspended-dən əvvəl son zəmanətli çağırış
func applicationDidEnterBackground(_ application: UIApplication) {
// Yaddaşdan boşaldılmanı yaşamalı olan hər şeyi saxlayırıq
savePersistentState()
saveNavigationStack()
// Lazım olduqda əlavə vaxt tələb edirik
let task = application.beginBackgroundTask {
application.endBackgroundTask(task)
}
}
// Suspended-dən qayıtma — isti start
func applicationWillEnterForeground(_ application: UIApplication) {
// Tətbiq Suspended-də idi, işə qayıdırıq
print("Suspended və ya Background-dan qayıtma")
}
// Yaddaşdan boşaltmadan sonra tam bərpa
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Əgər bu Suspended-dən boşaltmadan sonra soyuq startdırsa —
// state restoration-u bərpa edirik
return true
}
private func savePersistentState() {
UserDefaults.standard.set(Date(), forKey: "lastActiveDate")
}
private func saveNavigationStack() {
guard let rootVC = window?.rootViewController else { return }
// Cari naviqasiya stack-ini saxlayırıq
if let navController = rootVC as? UINavigationController {
let vcClasses = navController.viewControllers.map { type(of: $0) }
UserDefaults.standard.set(vcClasses.map { NSStringFromClass($0) }, forKey: "navStack")
}
}
}Kod iOS-da Suspended-in kritik vacib işlənməsini göstərir. applicationDidEnterBackground — son zəmanətli çağırış. Bütün məlumatların saxlanması burada baş verməlidir: istifadəçi vəziyyəti, naviqasiya stack-i, qaralamalar, taymerlər. applicationWillEnterForeground Suspended və ya Background-dan qayıtdıqda çağırılır. didFinishLaunchingWithOptions — yalnız soyuq startda, tətbiq Suspended-dən sonra yaddaşdan boşaldıldıqda.
Android-də birbaşa analoqu yoxdur iOS Suspended. Android tətbiqləri icra kontekstini qoruyaraq yaddaşda dondurmur. Bunun əvəzinə Android ya prosesi fonda saxlayır (Background), ya da onu başa çatdırır (Not Running). Lakin Android 11+-də (API 30) App Freezer mexanizmi meydana çıxdı, o SIGSTOP siqnalı ilə fon proseslərinin icrasını dayandırır. Bu, Suspended-in funksional analoqudur, lakin əhəmiyyətli fərqlərlə.
App Freezer — Android yaddaş idarəetmə sisteminin bir hissəsidir. Tətbiq uzun müddət fonda qaldıqda və aktiv bildirişləri olmadıqda, sistem ona SIGSTOP göndərir, bütün axınları dayandırır. Tətbiq ön plana qayıtdıqda SIGCONT göndərilir və icra bərpa olunur. iOS-dan əsas fərq: App Freezer vəziyyətin qorunmasına zəmanət vermir — dondurma zamanı proses öldürülərsə, yaddaşdakı məlumatlar itirilə bilər.
Android-də SavedStateHandle-dən istifadə etmək tövsiyə olunur ViewModel-də hər hansı proses başa çatdıqda avtomatik vəziyyətin saxlanması üçün. SavedStateHandle məlumatları Bundle-də onSaveInstanceState vasitəsilə saxlayır, bu həm App Freezer, həm də Process Death-dən sağ çıxır. iOS-dan fərqli olaraq, burada Suspended-dən boşaltma müstəsna haldır, Android-də Process Death normal davranışdır və həmişə gözlənilməlidir.
// SavedStateHandle — Android-də Process Death-dən qurtuluş
class CheckoutViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// App Freezer-dən sonra da prosesdən sağ çıxacaq vəziyyət
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
}
}
// App Freezer halında onStop-da saxlama
class MainActivity : AppCompatActivity() {
override fun onStop() {
super.onStop()
// Dondurmanı yaşamalı olan məlumatları saxlayırıq
saveDraftData()
// Dondurulmuş vəziyyətdə lazım olmayan resursları boşaldırıq
releaseHeavyResources()
// Tətbiqin dondurulacağı barədə xəbərdarlıq edirik
// (Debug üçün jurnal)
Log.d("Lifecycle", "Activity dayandırıldı — mümkün App Freeze")
}
}Kod Android-də Suspended analoqunun işlənməsi yanaşmasını göstərir. SavedStateHandle ViewModel-də Process Death zamanı avtomatik məlumatları saxlayır və bərpa edir. onStop — mümkün App Freezer və ya prosesin başa çatmasından əvvəl son zəmanətli hadisə. Sifariş formasının vəziyyəti, səbətdəki məhsulların siyahısı — bütün bu məlumatlar SavedStateHandle sayəsində dondurmadan sağ çıxır. Ağır resurslar üçün (bitmaplar, verilənlər bazası kursorları) onStop yaddaşı boşaltmaq yeridir.
State Restoration — tətbiq yaddaşdan boşaldıldıqdan sonra UI vəziyyətinin saxlanması və bərpası üçün iOS-un daxili mexanizmidir. Əgər tətbiq Suspended-də idisə və sistem onu boşaltdısa, növbəti soyuq startda state restoration naviqasiya stack-ini, sürüşdürmə mövqeyini, forma vəziyyətini və digər UI elementlərini bərpa edir. İstifadəçi dayandığı ekrana qayıdır.
State Restoration UIViewControllerRestoration və UIStateRestoring protokolları vasitəsilə işləyir. Tərtibatçı bərpa etmək istədiyi hər ViewController və View-ə restorationIdentifier təyin edir. Background-a keçərkən iOS bu obyektlərin vəziyyətini kodlaşdırır. Boşaltmadan sonra qayıtdıqda iOS yeni obyektlər yaradır və saxlanmış vəziyyəti dekodlaşdırır. State restoration olmadan istifadəçi dayandığı yerin əvəzinə soyuq startdan sonra boş ekran görəcək.
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
// Məlumatların yüklənməsindən sonra mövqeni bərpa edirik
}
}
}
// AppDelegate — State Restoration-un aktivləşdirilməsi
func application(
_ application: UIApplication,
shouldSaveSecureApplicationState coder: NSCoder
) -> Bool {
return true
}
func application(
_ application: UIApplication,
shouldRestoreSecureApplicationState coder: NSCoder
) -> Bool {
return true
}Kod iOS-da State Restoration-un tətbiqini göstərir. restorationIdentifier və restorationClass hər bərpa olunan ViewController üçün lazımdır. encodeRestorableState/decodeRestorableState NSCoder vasitəsilə məlumatları saxlayır və yükləyir. AppDelegate-də shouldSaveSecureApplicationState və shouldRestoreSecureApplicationState şifrələnmiş vəziyyətin saxlanmasını aktivləşdirir. iOS 12+-dən verilənlərin qorunması üçün secure encoding (NSSecureCoding) tövsiyə olunur.
Birinci qayda — heç vaxt tətbiqin Suspended-dən qayıdacağını düşünməyin. Sistem istənilən anda tətbiqi boşalda bilər. Bütün kritik vacib məlumatlar Suspended-ə keçməzdən əvvəl — yəni applicationDidEnterBackground və ya onStop-da — davamlı yaddaşda saxlanmalıdır. UserDefaults, Core Data, File Manager — uyğun yaddaşlar. Yaddaş (dəyişənlər, xüsusiyyətlər) Suspended-dən sağ çıxmalı olan məlumatlar üçün etibarsız yaddaşdır.
İkinci qayda — Suspended-dən əvvəl resursları boşaldın. Fayl deskriptorlarını bağlayın, GPU yaddaşını (Metal, Core Graphics) boşaldın, şəbəkə birləşmələrini bağlayın. Tətbiq Suspended-də CPU istehlak etməsə də, tutulmuş resurslar digər tətbiqlər üçün bloklanır. iOS-da Suspended-də açıq soketlər saxlamaq olmaz — Suspended-dən qayıtdıqda onlar işlək olmaya bilər, bu səhvlərə səbəb olar.
Üçüncü qayda — Suspended-dən qayıtmağı gözləyən zamandan asılı məntiq yerləşdirməyin. Taymerlər, callback-lər və şəbəkə aktivliyi Suspended-də dayanır. Tətbiq bir neçə saat Suspended-də olubsa, qayıtdıqda taymer səhv işləyə bilər. Qayıtdıqda məlumatların aktuallığını yoxlayın — ola bilsin keş köhnəlib, avtorizasiya tokeni isə müddəti bitib.
Dördüncü qayda — bütün ekranlar üçün State Restoration-dan istifadə edin, xüsusilə daxiletmə formaları, sürüşdürülən siyahılar və detallı ekranlar üçün. State restoration olmadan, boşaldılmış Suspended-dən qayıtdıqdan sonra istifadəçi dayandığı yeri deyil, tətbiqin ilkin ekranını görəcək. Bu istifadəçi təcrübəsini pisləşdirir və onu hərəkətləri təkrarlamağa məcbur edir.
import UIKit
// Yoxlama: tətbiq yaddaşdan boşaldılıbmı?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Saxlanmış vəziyyətin olub-olmadığını yoxlayırıq
if UserDefaults.standard.object(forKey: "navStack") != nil {
// Tətbiq Suspended-dən boşaldılıb
// Vəziyyəti bərpa etmək lazımdır
restoreNavigationStack()
} else {
// Not Running-dən təmiz soyuq start
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)
}
}
}Kod tətbiqin Suspended-dən boşaldılıb-boşaldılmadığını müəyyən etmək təcrübəsini göstərir. UserDefaults-ın yoxlanması saxlanmış naviqasiya stack-inin mövcudluğuna görə boşaltmadan sonra soyuq startı təmiz soyuq startdan ayırmağa imkan verir. Birinci halda naviqasiya stack-i bərpa olunur, ikincidə — onboarding və ya əsas ekran göstərilir. Bu yanaşma NSCoder-in kifayət etmədiyi hallarda daxili State Restoration-u tamamlayır.
Tez-tez verilən suallar
Məhdudiyyətsiz — bir neçə saniyədən bir neçə günə qədər. iOS-da Suspended üçün vaxt aşımı yoxdur. Tətbiq sistem resurs çatışmazlığı səbəbindən onu boşaltmaq qərarına gələnə qədər yaddaşda qalacaq. Praktikada tətbiqlər cihazın operativ yaddaşının həcmindən və aktiv tətbiqlərin sayından asılı olaraq 15 dəqiqədən bir neçə saata qədər Suspended-də qalır.
Xeyr. applicationWillTerminate çağırılmır tətbiq Suspended-dən boşaldıldıqda. Sistem sadəcə tətbiqə bildiriş vermədən yaddaşı boşaldır. Bu, bütün məlumatların saxlanmasının applicationDidEnterBackground-da baş verməsinin daha bir səbəbidir. applicationWillTerminate yalnız istifadəçi tətbiqi App Switcher-dən sürüşdürərək əl ilə başa çatdırdıqda çağırılır.
Birbaşa analoqu yoxdur. Android 11+-də App Freezer meydana çıxdı, o SIGSTOP vasitəsilə fon proseslərini dayandırır — bu funksional olaraq Suspended-ə bənzəyir. Lakin Android tətbiqləri istənilən anda Process Death-ə hesablanaraq layihələndirilməlidir. ViewModel-də SavedStateHandle və onSaveInstanceState-dən istifadə edin ki, vəziyyət həm App Freezer, həm də Process Death-dən sağ çıxsın.
iOS-da birbaşa yoxlama API-i yoxdur. Dolayı metod: UserDefaults-ı yoxlayın didFinishLaunchingWithOptions-da saxlanmış vəziyyətin mövcudluğuna görə. Vəziyyət varsa — tətbiq Suspended-dən boşaldılıb və soyuq start edir. Vəziyyət yoxdursa — təmiz soyuq start. SwiftUI-də scenePhase.background-da flag saxlaya və növbəti işə salmada yoxlaya bilərsiniz.
Suspended-ə keçərkən iOS snapshot — tətbiqin cari UI-nin ekran görüntüsünü çəkir. Bu görüntü App Switcher-də və tətbiqə qayıtdıqda (ərimə animasiyası kimi) göstərilir. Tətbiq məxfi məlumatlar ehtiva edirsə, snapshot onları aşkar edə bilər. Qoruma üçün UIApplication.shouldSnapshotSecureApp (iOS 16+) istifadə edin və ya applicationDidEnterBackground-da blur-overlay tətbiq edin.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun