Suspended — status ditangguhkan dari siklus hidup aplikasi iOS, di mana aplikasi dibekukan di memori tetapi tidak mengeksekusi kode. Kami menunjukkan cara kerja Suspended, risiko apa yang ditimbulkan oleh pembekuan aplikasi di latar belakang, bagaimana iOS mengelola pembongkaran aplikasi Suspended, dan cara mengimplementasikan state restoration untuk pemulihan mulus setelah kembali dari Suspended.
Poin Utama
Suspended — status siklus hidup aplikasi iOS di mana aplikasi berada di memori operasional perangkat tetapi tidak mengeksekusi kode apa pun. Ini adalah status akhir sebelum penghentian penuh: aplikasi bertransisi ke Suspended dari Background setelah menyelesaikan semua tugas latar belakang atau setelah batas waktu habis. Dalam Suspended, aplikasi sepenuhnya dibekukan — semua thread dihentikan, timer tidak berfungsi, aktivitas jaringan tidak ada.
Suspended — fitur unik iOS yang tidak ada dalam siklus hidup standar Android. Alasannya adalah arsitektur manajemen proses yang berbeda. iOS menyimpan gambar aplikasi di memori (analog dengan hibernasi di desktop) sehingga saat pengguna kembali, antarmuka segera dipulihkan tanpa cold start. Android tidak memiliki Suspended — prosesnya ada dan dapat mengeksekusi kode (Background), atau dihentikan (Not Running), meskipun Android dapat menghentikan eksekusi thread melalui LMK.
Bagi pengguna, Suspended terlihat seperti pemulihan instan: ia beralih antar aplikasi melalui App Switcher, dan setiap aplikasi terbuka dari tempat yang ditinggalkan. Ini menciptakan ilusi bahwa semua aplikasi berjalan secara bersamaan. Kenyataannya, sebagian besar dari mereka dibekukan dalam Suspended. Hot start dari Suspended berkali-kali lebih cepat daripada cold start dari Not Running, karena kode sudah dimuat di memori.
iOS melacak status semua aplikasi dan membuat keputusan tentang pembongkaran aplikasi Suspended berdasarkan memori yang tersedia. Ketika memori tidak mencukupi, sistem mulai membongkar aplikasi Suspended, dimulai dari yang paling lama berada dalam status ini. Jika memori masih tidak mencukupi, sistem memindahkan aplikasi dari Background dan Inactive ke Suspended, lalu membongkarnya. Proses ini sepenuhnya transparan bagi pengguna — ia hanya melihat ikon aplikasi di App Switcher, yang saat diklik memulai cold start.
| Karakteristik | Suspended (iOS) | Background (iOS) | Background (Android) |
|---|---|---|---|
| Kode dijalankan | Tidak | Ya (terbatas) | Ya (terbatas) |
| Di memori | Ya | Ya | Ya |
| Konsumsi CPU | 0% | Rendah | Rendah |
| Hot start | Ya — pemulihan instan | Ya — melalui Inactive | Tidak — proses mungkin telah dimatikan |
| Batas waktu | Tidak — bisa di memori berjam-jam | ~30 detik (setelah beginBackgroundTask) | Tergantung versi API |
| Pembongkaran sistem | Saat memori tidak mencukupi | Saat memori sangat tidak mencukupi | LMK (Low Memory Killer) |
| Kembali bekerja | Dari App Switcher — instan | Dari App Switcher — melalui Inactive | Cold start |
| State Restoration | Disarankan | Tidak diperlukan | SavedStateHandle |
Di iOS Suspended tercapai secara otomatis setelah menyelesaikan semua tugas latar belakang. Sistem memanggil applicationDidEnterBackground, memberikan waktu untuk mengeksekusi beginBackgroundTask (sekitar 30 detik), setelah itu secara paksa menghentikan semua thread dan memindahkan aplikasi ke status Suspended. Objek di memori dipertahankan, tetapi tidak ada kode yang dijalankan — aplikasi dibekukan dalam status saat ini.
Momen yang sangat penting: applicationDidEnterBackground — metode terakhir yang dijamin dipanggil sebelum Suspended. Setelah ini, aplikasi tidak menerima pemberitahuan apa pun tentang pembongkaran dari memori. Jika pengguna atau sistem mematikan aplikasi yang berada dalam Suspended, baik applicationWillTerminate maupun applicationDidEnterBackground tidak dipanggil lagi. Oleh karena itu, semua penyimpanan data harus terjadi di applicationDidEnterBackground, bukan di applicationWillTerminate.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Panggilan terjamin terakhir sebelum Suspended
func applicationDidEnterBackground(_ application: UIApplication) {
// Menyimpan semua yang harus bertahan dari pembongkaran memori
savePersistentState()
saveNavigationStack()
// Meminta waktu tambahan jika diperlukan
let task = application.beginBackgroundTask {
application.endBackgroundTask(task)
}
}
// Kembali dari Suspended — hot start
func applicationWillEnterForeground(_ application: UIApplication) {
// Aplikasi berada di Suspended, kembali bekerja
print("Kembali dari Suspended atau Background")
}
// Pemulihan penuh setelah pembongkaran dari memori
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Jika ini cold start setelah pembongkaran dari Suspended —
// memulihkan state restoration
return true
}
private func savePersistentState() {
UserDefaults.standard.set(Date(), forKey: "lastActiveDate")
}
private func saveNavigationStack() {
guard let rootVC = window?.rootViewController else { return }
// Menyimpan tumpukan navigasi saat ini
if let navController = rootVC as? UINavigationController {
let vcClasses = navController.viewControllers.map { type(of: $0) }
UserDefaults.standard.set(vcClasses.map { NSStringFromClass($0) }, forKey: "navStack")
}
}
}Kode menunjukkan penanganan kritis Suspended di iOS. applicationDidEnterBackground — panggilan terjamin terakhir. Semua penyimpanan data harus terjadi di sini: status pengguna, tumpukan navigasi, draf, timer. applicationWillEnterForeground dipanggil saat kembali dari Suspended atau Background. didFinishLaunchingWithOptions — hanya saat cold start, ketika aplikasi telah dibongkar dari memori setelah Suspended.
Di Android tidak ada analog langsung dari Suspended iOS. Android tidak membekukan aplikasi di memori dengan mempertahankan konteks eksekusi. Sebaliknya, Android baik mempertahankan proses di latar belakang (Background) atau mengakhirinya (Not Running). Namun, pada Android 11+ (API 30) muncul mekanisme App Freezer, yang menghentikan eksekusi proses latar belakang dengan sinyal SIGSTOP. Ini adalah analog fungsional dari Suspended, tetapi dengan perbedaan penting.
App Freezer — bagian dari sistem manajemen memori Android. Ketika aplikasi lama berada di latar belakang dan tidak memiliki notifikasi aktif, sistem mengirimkan SIGSTOP, menghentikan semua thread. Saat aplikasi kembali ke latar depan, SIGCONT dikirim dan eksekusi dilanjutkan. Perbedaan utama dari iOS: App Freezer tidak menjamin pelestarian status — data di memori dapat hilang jika proses dimatikan selama pembekuan.
Di Android disarankan menggunakan SavedStateHandle di ViewModel untuk menyimpan status secara otomatis saat proses berakhir. SavedStateHandle menyimpan data di Bundle melalui onSaveInstanceState, yang bertahan baik dari App Freezer maupun Process Death. Berbeda dengan iOS, di mana pembongkaran dari Suspended adalah situasi luar biasa, di Android Process Death adalah perilaku normal yang harus selalu diantisipasi.
// SavedStateHandle — penyelamat dari Process Death di Android
class CheckoutViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// Status yang bertahan dari proses bahkan setelah 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
}
}
// Penyimpanan di onStop untuk kasus App Freezer
class MainActivity : AppCompatActivity() {
override fun onStop() {
super.onStop()
// Menyimpan data yang harus bertahan dari pembekuan
saveDraftData()
// Membebaskan sumber daya yang tidak diperlukan dalam status beku
releaseHeavyResources()
// Memperingatkan bahwa aplikasi akan dibekukan
// (Pencatatan untuk debugging)
Log.d("Lifecycle", "Activity dihentikan — kemungkinan App Freeze")
}
}Kode menunjukkan pendekatan penanganan analog Suspended di Android. SavedStateHandle di ViewModel secara otomatis menyimpan dan memulihkan data saat Process Death. onStop — peristiwa terakhir yang dijamin sebelum kemungkinan App Freezer atau penghentian proses. Status formulir pesanan, daftar produk di keranjang — semua data ini bertahan dari pembekuan berkat SavedStateHandle. Untuk sumber daya berat (bitmap, kursor database) onStop adalah tempat untuk membebaskan memori.
State Restoration — mekanisme bawaan iOS untuk menyimpan dan memulihkan status UI setelah aplikasi dibongkar dari memori. Jika aplikasi berada dalam Suspended dan sistem membongkarnya, pada cold start berikutnya state restoration memulihkan tumpukan navigasi, posisi gulir, status formulir, dan elemen UI lainnya. Pengguna kembali ke layar yang sama tempat ia berhenti.
State Restoration bekerja melalui protokol UIViewControllerRestoration dan UIStateRestoring. Pengembang memberikan restorationIdentifier ke setiap ViewController dan View yang ingin dipulihkan. Saat masuk ke Background, iOS mengkodekan status objek-objek ini. Setelah kembali dari pembongkaran, iOS membuat objek baru dan mendekode status yang disimpan. Tanpa state restoration, pengguna akan melihat layar kosong setelah cold start, bukan tempat di mana ia berhenti.
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
// Memulihkan posisi setelah memuat data
}
}
}
// AppDelegate — aktivasi State Restoration
func application(
_ application: UIApplication,
shouldSaveSecureApplicationState coder: NSCoder
) -> Bool {
return true
}
func application(
_ application: UIApplication,
shouldRestoreSecureApplicationState coder: NSCoder
) -> Bool {
return true
}Kode menunjukkan implementasi State Restoration di iOS. restorationIdentifier dan restorationClass diperlukan untuk setiap ViewController yang akan dipulihkan. encodeRestorableState/decodeRestorableState menyimpan dan memuat data melalui NSCoder. Di AppDelegate, shouldSaveSecureApplicationState dan shouldRestoreSecureApplicationState mengaktifkan penyimpanan status terenkripsi. Sejak iOS 12+ dianjurkan menggunakan secure encoding (NSSecureCoding) untuk melindungi data.
Aturan pertama — jangan pernah menganggap aplikasi akan kembali dari Suspended. Sistem dapat membongkar aplikasi kapan saja. Semua data yang sangat penting harus disimpan di penyimpanan permanen sebelum bertransisi ke Suspended — yaitu di applicationDidEnterBackground atau onStop. UserDefaults, Core Data, File Manager — penyimpanan yang sesuai. Memori (variabel, properti) — penyimpanan yang tidak dapat diandalkan untuk data yang harus bertahan dari Suspended.
Aturan kedua — bebaskan sumber daya sebelum Suspended. Tutup deskriptor file, bebaskan memori GPU (Metal, Core Graphics), tutup koneksi jaringan. Meskipun aplikasi tidak mengonsumsi CPU dalam Suspended, sumber daya yang terpakai diblokir untuk aplikasi lain. Di iOS dalam Suspended, soket terbuka tidak boleh dipertahankan — saat kembali dari Suspended, soket mungkin tidak berfungsi, yang akan menyebabkan kesalahan.
Aturan ketiga — jangan tempatkan logika yang bergantung pada waktu dalam menunggu kembali dari Suspended. Timer, callback, dan aktivitas jaringan berhenti dalam Suspended. Jika aplikasi berada dalam Suspended selama beberapa jam, saat kembali timer mungkin berfungsi tidak benar. Periksa keaktualan data saat kembali — mungkin cache sudah usang dan token otorisasi telah kedaluwarsa.
Aturan keempat — gunakan State Restoration untuk semua layar, terutama untuk formulir input, daftar yang dapat digulir, dan layar detail. Tanpa state restoration, setelah kembali dari Suspended yang dibongkar, pengguna akan melihat layar awal aplikasi, bukan tempat di mana ia berhenti. Ini memperburuk pengalaman pengguna dan memaksa pengguna untuk mengulangi tindakan.
import UIKit
// Pemeriksaan: apakah aplikasi telah dibongkar dari memori?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Memeriksa apakah ada status yang disimpan
if UserDefaults.standard.object(forKey: "navStack") != nil {
// Aplikasi telah dibongkar dari Suspended
// Perlu memulihkan status
restoreNavigationStack()
} else {
// Cold start bersih dari 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)
}
}
}Kode menunjukkan praktik menentukan apakah aplikasi telah dibongkar dari Suspended. Pemeriksaan UserDefaults untuk keberadaan tumpukan navigasi yang disimpan memungkinkan membedakan cold start setelah pembongkaran dari cold start bersih. Dalam kasus pertama, tumpukan navigasi dipulihkan; dalam kasus kedua, onboarding atau layar utama ditampilkan. Pendekatan ini melengkapi State Restoration bawaan untuk kasus di mana NSCoder tidak mencukupi.
Pertanyaan yang Sering Diajukan
Tidak terbatas — dari beberapa detik hingga beberapa hari. iOS tidak memiliki batas waktu untuk Suspended. Aplikasi akan tetap di memori sampai sistem memutuskan untuk membongkarnya karena kekurangan sumber daya. Dalam praktiknya aplikasi tetap di Suspended dari 15 menit hingga beberapa jam, tergantung pada jumlah RAM perangkat dan jumlah aplikasi aktif.
Tidak. applicationWillTerminate tidak dipanggil saat aplikasi dibongkar dari Suspended. Sistem hanya membebaskan memori tanpa memberi tahu aplikasi. Ini adalah alasan lain mengapa semua penyimpanan data harus terjadi di applicationDidEnterBackground. applicationWillTerminate hanya dipanggil ketika pengguna secara manual mengakhiri aplikasi dengan menggesek dari App Switcher.
Tidak ada analog langsung. Di Android 11+ muncul App Freezer, yang menghentikan proses latar belakang melalui SIGSTOP — ini secara fungsional mirip dengan Suspended. Namun, aplikasi Android harus dirancang dengan mempertimbangkan Process Death kapan saja. Gunakan SavedStateHandle di ViewModel dan onSaveInstanceState untuk menyimpan status yang akan bertahan baik dari App Freezer maupun Process Death.
Di iOS tidak ada API langsung untuk memeriksa. Metode tidak langsung: periksa UserDefaults untuk keberadaan status yang disimpan di didFinishLaunchingWithOptions. Jika status ada — aplikasi telah dibongkar dari Suspended dan memulai cold start. Jika tidak ada status — cold start bersih. Di SwiftUI, Anda dapat menyimpan flag di scenePhase.background dan memeriksanya saat startup berikutnya.
Saat bertransisi ke Suspended, iOS mengambil snapshot — tangkapan layar dari UI aplikasi saat ini. Tangkapan layar ini ditampilkan di App Switcher dan saat kembali ke aplikasi (sebagai animasi pencairan). Jika aplikasi berisi data rahasia, snapshot dapat mengungkapkannya. Untuk perlindungan, gunakan UIApplication.shouldSnapshotSecureApp (iOS 16+) atau terapkan blur-overlay di applicationDidEnterBackground.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga