Suspended — iOS uygulama yaşam döngüsünün askıya alınmış bir durumudur; uygulama bellekte dondurulur ancak kod çalıştırmaz. Suspended'ın nasıl çalıştığını, arka planda uygulama dondurmanın getirdiği riskleri, iOS'un Suspended uygulamaların boşaltılmasını nasıl yönettiğini ve Suspended'den döndükten sonra kesintisiz kurtarma için state restoration'ın nasıl uygulanacağını gösteriyoruz.
Temel Noktalar
Suspended, iOS uygulama yaşam döngüsünün bir durumudur; uygulama cihazın RAM'inde bulunur ancak hiçbir kod çalıştırmaz. Bu, tam sonlandırmadan önceki son durumdur: uygulama, tüm arka plan görevlerini tamamladıktan veya bir zaman aşımı süresi dolduktan sonra Background'dan Suspended'e geçer. Suspended'de uygulama tamamen dondurulur — tüm iş parçacıkları durdurulur, zamanlayıcılar çalışmaz ve ağ etkinliği olmaz.
Suspended, iOS'un benzersiz bir özelliğidir ve standart Android yaşam döngüsünde bulunmaz. Bunun nedeni, farklı süreç yönetim mimarileridir. iOS, uygulamanın görüntüsünü bellekte korur (masaüstü hazırda bekletmeye benzer), böylece kullanıcı geri döndüğünde arayüz soğuk başlatma olmadan anında geri yüklenebilir. Android'de Suspended yoktur — bir süreç ya var olur ve kod çalıştırabilir (Background) ya da sonlandırılır (Not Running), ancak Android LMK aracılığıyla iş parçacığı yürütmesini durdurabilir.
Kullanıcı için Suspended, anında geri yükleme gibi görünür: App Switcher aracılığıyla uygulamalar arasında geçiş yaparlar ve her uygulama bıraktıkları yerden açılır. Bu, tüm uygulamaların aynı anda çalıştığı yanılsamasını yaratır. Gerçekte, çoğu Suspended'de dondurulmuştur. Suspended'den sıcak başlatma, Not Running'dan soğuk başlatmaya göre kat kat daha hızlıdır, çünkü kod zaten belleğe yüklenmiştir.
iOS, tüm uygulamaların durumunu izler ve kullanılabilir belleğe göre Suspended uygulamaları boşaltmaya karar verir. Bellek azaldığında, sistem Suspended uygulamaları boşaltmaya başlar, en uzun süre bu durumda olanlardan başlayarak. Bellek hala yetersizse, sistem Background ve Inactive'deki uygulamaları Suspended'e geçirir ve ardından boşaltır. Bu süreç kullanıcı için tamamen şeffaftır — kullanıcı App Switcher'da uygulama simgesini görür ve dokunduğunda soğuk başlatma başlatır.
| Özellik | Suspended (iOS) | Background (iOS) | Background (Android) |
|---|---|---|---|
| Kod çalıştırır | Hayır | Evet (sınırlı) | Evet (sınırlı) |
| Bellekte | Evet | Evet | Evet |
| CPU tüketimi | %0 | Düşük | Düşük |
| Sıcak başlatma | Evet — anında geri yükleme | Evet — Inactive aracılığıyla | Hayır — süreç sonlandırılmış olabilir |
| Zaman aşımı | Hayır — saatlerce bellekte kalabilir | ~30 saniye (beginBackgroundTask sonrası) | API sürümüne bağlı |
| Sistem tarafından boşaltma | Bellek azaldığında | Bellek kritik derecede azaldığında | LMK (Low Memory Killer) |
| İşe dönüş | App Switcher'dan — anında | App Switcher'dan — Inactive aracılığıyla | Soğuk başlatma |
| State Restoration | Önerilir | Gerekli değil | SavedStateHandle |
iOS'ta, tüm arka plan görevleri tamamlandıktan sonra Suspended otomatik olarak ulaşılır. Sistem applicationDidEnterBackground'ı çağırır, beginBackgroundTask'ı yürütmek için zaman verir (yaklaşık 30 saniye), ardından tüm iş parçacıklarını zorla durdurur ve uygulamayı Suspended'e geçirir. Bellekteki nesneler korunur, ancak hiçbir kod çalıştırılmaz — uygulama mevcut durumunda dondurulur.
Kritik derecede önemli bir nokta: applicationDidEnterBackground, Suspended'den önce çağrılması garanti edilen son yöntemdir. Bundan sonra uygulama, bellek boşaltma hakkında herhangi bir bildirim almaz. Kullanıcı veya sistem Suspended'deki uygulamayı sonlandırırsa, ne applicationWillTerminate ne de applicationDidEnterBackground yeniden çağrılır. Bu nedenle, tüm veri kaydetme işlemi applicationDidEnterBackground'da gerçekleşmelidir, applicationWillTerminate'te değil.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Suspended'den önce son garantili çağrı
func applicationDidEnterBackground(_ application: UIApplication) {
// Bellek boşaltmadan kurtulması gereken her şeyi kaydet
savePersistentState()
saveNavigationStack()
// Gerekirse ek süre iste
let task = application.beginBackgroundTask {
application.endBackgroundTask(task)
}
}
// Suspended'den dönüş — sıcak başlatma
func applicationWillEnterForeground(_ application: UIApplication) {
// Uygulama Suspended'deydi, çalışmaya devam
print("Suspended veya Background'dan dönüş")
}
// Bellek boşaltma sonrası tam kurtarma
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Bu, Suspended'den boşaltma sonrası soğuk başlatma ise —
// state restoration'ı geri yükle
return true
}
private func savePersistentState() {
UserDefaults.standard.set(Date(), forKey: "lastActiveDate")
}
private func saveNavigationStack() {
guard let rootVC = window?.rootViewController else { return }
// Mevcut gezinme yığınını kaydet
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'ta Suspended'in kritik derecede önemli işlenmesini gösterir. applicationDidEnterBackground son garantili çağrıdır. Tüm veri kaydetme burada gerçekleşmelidir: kullanıcı durumu, gezinme yığını, taslaklar, zamanlayıcılar. applicationWillEnterForeground, Suspended veya Background'dan dönüşte çağrılır. didFinishLaunchingWithOptions — yalnızca uygulama Suspended sonrası bellekten boşaltıldığında soğuk başlatmada çağrılır.
Android'de, iOS Suspended'in doğrudan bir benzeri yoktur. Android, yürütme bağlamını koruyarak uygulamaları bellekte dondurmaz. Bunun yerine, Android süreci arka planda tutar veya sonlandırır. Ancak, Android 11+ (API 30) üzerinde App Freezer adlı bir mekanizma tanıtılmıştır ve SIGSTOP sinyalini kullanarak arka plan süreçlerinin yürütmesini durdurur. Bu, işlevsel olarak Suspended'e benzer, ancak önemli farklılıklar vardır.
App Freezer, Android bellek yönetim sisteminin bir parçasıdır. Bir uygulama aktif bildirim olmadan uzun süre arka planda kaldığında, sistem SIGSTOP gönderir ve tüm iş parçacıklarını durdurur. Uygulama ön plana döndüğünde SIGCONT gönderilir ve yürütme devam eder. iOS'tan temel fark: App Freezer durum korumasını garanti etmez — dondurma sırasında süreç sonlandırılırsa bellekteki veriler kaybolabilir.
Android'de, herhangi bir süreç sonlandırmasında otomatik durum koruması için ViewModel'de SavedStateHandle kullanılması önerilir. SavedStateHandle, onSaveInstanceState aracılığıyla bir Bundle'da veri kaydeder ve hem App Freezer'dan hem de Process Death'ten kurtulur. iOS'un aksine, Suspended'den boşaltmanın istisnai bir durum olduğu iOS'ta, Android'de Process Death her zaman beklenmesi gereken normal bir davranıştır.
// SavedStateHandle — Android'de Process Death'ten kurtuluş
class CheckoutViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// App Freezer'dan sonra bile süreci atlatan durum
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 durumunda onStop'a kaydet
class MainActivity : AppCompatActivity() {
override fun onStop() {
super.onStop()
// Dondurmadan kurtulması gereken verileri kaydet
saveDraftData()
// Dondurulmuş durumda gerekli olmayan kaynakları serbest bırak
releaseHeavyResources()
// Uygulamanın dondurulacağını bildir
// (Hata ayıklama için günlük kaydı)
Log.d("Lifecycle", "Activity stopped — olası App Freeze")
}
}Kod, Android'de Suspended benzerini işleme yaklaşımını gösterir. ViewModel'deki SavedStateHandle, Process Death sırasında verileri otomatik olarak kaydeder ve geri yükler. onStop, olası bir App Freezer veya süreç sonlandırmasından önceki son garantili olaydır. Ödeme formu durumu, sepetteki ürün listesi — tüm bu veriler, SavedStateHandle sayesinde dondurmadan kurtulur. Ağır kaynaklar (bitmap'ler, DB imleçleri) için onStop, belleği serbest bırakma yeridir.
State Restoration, uygulama bellekten boşaltıldıktan sonra UI durumunu kaydetmek ve geri yüklemek için yerleşik bir iOS mekanizmasıdır. Uygulama Suspended'deyse ve sistem onu boşalttıysa, bir sonraki soğuk başlatmada state restoration gezinme yığınını, kaydırma konumunu, form durumunu ve diğer UI öğelerini geri yükler. Kullanıcı kaldığı yere geri döner.
State Restoration, UIViewControllerRestoration ve UIStateRestoring protokolleri aracılığıyla çalışır. Geliştirici, geri yüklemek istediği her ViewController ve View'e bir restorationIdentifier atar. Arka plana gidildiğinde, iOS bu nesnelerin durumunu kodlar. Boşaltma sonrası geri dönüşte, iOS yeni nesneler oluşturur ve kaydedilen durumu çözer. State restoration olmadan, kullanıcı soğuk başlatma sonrası kaldığı yer yerine boş bir ekran görür.
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
// Veri yükleme sonrası konumu geri yükle
}
}
}
// AppDelegate — State Restoration'ı etkinleştirme
func application(
_ application: UIApplication,
shouldSaveSecureApplicationState coder: NSCoder
) -> Bool {
return true
}
func application(
_ application: UIApplication,
shouldRestoreSecureApplicationState coder: NSCoder
) -> Bool {
return true
}Kod, iOS'ta State Restoration'ın uygulanmasını gösterir. Geri yüklenebilir her ViewController için restorationIdentifier ve restorationClass gereklidir. encodeRestorableState/decodeRestorableState, NSCoder aracılığıyla verileri kaydeder ve yükler. AppDelegate'te, shouldSaveSecureApplicationState ve shouldRestoreSecureApplicationState şifreli durum kaydetmeyi etkinleştirir. iOS 12+ üzerinde, veri koruması için güvenli kodlama (NSSecureCoding) kullanılması önerilir.
Birinci kural — uygulamanın Suspended'den döneceğini asla varsaymayın. Sistem uygulamayı her an boşaltabilir. Tüm kritik derecede önemli veriler, Suspended'e geçişten önce kalıcı depolamaya kaydedilmelidir — yani applicationDidEnterBackground veya onStop'da. UserDefaults, Core Data, File Manager — uygun depolama seçenekleri. Bellek (değişkenler, özellikler), Suspended'den kurtulması gereken veriler için güvenilmez bir depolamadır.
İkinci kural — Suspended'den önce kaynakları serbest bırakın. Dosya tanımlayıcıları kapatın, GPU belleğini (Metal, Core Graphics) serbest bırakın, ağ bağlantılarını kapatın. Uygulama Suspended'de CPU tüketmese de, tutulan kaynaklar diğer uygulamalar için bloke edilir. iOS'ta, Suspended'de açık soket tutulamaz — Suspended'den dönüşte çalışmayabilir ve hatalara neden olabilir.
Üçüncü kural — Suspended'den dönüşü bekleyen zamana bağımlı mantık yerleştirmeyin. Zamanlayıcılar, geri çağırmalar ve ağ etkinliği Suspended'de durur. Uygulama birkaç saat Suspended'de kaldıysa, dönüşte bir zamanlayıcı yanlış çalışabilir. Dönüşte veri geçerliliğini kontrol edin — önbellek güncelliğini yitirmiş olabilir ve yetkilendirme belirtecinin süresi dolmuş olabilir.
Dördüncü kural — tüm ekranlar için State Restoration kullanın, özellikle giriş formları, kaydırılabilir listeler ve detay ekranları için. State restoration olmadan, boşaltılmış bir Suspended'den döndükten sonra kullanıcı, kaldığı yer yerine uygulamanın başlangıç ekranını görür. Bu, kullanıcı deneyimini kötüleştirir ve kullanıcıyı eylemleri tekrarlamaya zorlar.
import UIKit
// Kontrol: uygulama bellekten boşaltıldı mı?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Kaydedilmiş durum olup olmadığını kontrol et
if UserDefaults.standard.object(forKey: "navStack") != nil {
// Uygulama Suspended'den boşaltıldı
// Durumu geri yüklemeli
restoreNavigationStack()
} else {
// Not Running'dan temiz soğuk başlatma
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, uygulamanın Suspended'den boşaltılıp boşaltılmadığını belirleme uygulamasını gösterir. Kaydedilmiş bir gezinme yığınının varlığı için UserDefaults'ı kontrol etme, boşaltma sonrası soğuk başlatmayı temiz soğuk başlatmadan ayırt etmeyi sağlar. İlk durumda, gezinme yığını geri yüklenir; ikincisinde, tanıtım veya ana ekran gösterilir. Bu yaklaşım, NSCoder'ın yetersiz olduğu durumlar için yerleşik State Restoration'ı tamamlar.
Sıkça Sorulan Sorular
Sınırsız — birkaç saniyeden birkaç güne kadar. iOS'un Suspended için zaman aşımı yoktur. Uygulama, sistem kaynak yetersizliği nedeniyle boşaltmaya karar verene kadar bellekte kalır. Uygulamada, uygulamalar cihazın RAM'ine ve aktif uygulama sayısına bağlı olarak 15 dakikadan birkaç saate kadar Suspended'de kalır.
Hayır. Uygulama Suspended'den boşaltıldığında applicationWillTerminate çağrılmaz. Sistem, uygulamayı bilgilendirmeden belleği basitçe serbest bırakır. Bu, tüm veri kaydetmenin applicationDidEnterBackground'da gerçekleşmesi gerektiğinin bir başka nedenidir. applicationWillTerminate yalnızca kullanıcı uygulamayı App Switcher'dan kaydırarak manuel olarak sonlandırdığında çağrılır.
Doğrudan bir benzeri yoktur. Android 11+ üzerinde, arka plan süreçlerini SIGSTOP aracılığıyla durduran App Freezer tanıtılmıştır — bu işlevsel olarak Suspended'e benzer. Ancak, Android uygulamaları her an Process Death olabileceğini varsayarak tasarlanmalıdır. Hem App Freezer'dan hem de Process Death'ten kurtulacak durumu kaydetmek için ViewModel'de SavedStateHandle ve onSaveInstanceState kullanın.
iOS'ta kontrol etmek için doğrudan bir API yoktur. Dolaylı bir yöntem: didFinishLaunchingWithOptions'ta kaydedilmiş durumun varlığı için UserDefaults'ı kontrol edin. Durum varsa — uygulama Suspended'den boşaltılmış ve soğuk başlatma yapıyor. Durum yoksa — temiz bir soğuk başlatmadır. SwiftUI'de, scenePhase.background'a bir işaret kaydedilebilir ve bir sonraki başlatmada kontrol edilebilir.
Suspended'e geçiş yaparken, iOS bir anlık görüntü — mevcut uygulama UI'ının ekran görüntüsünü çeker. Bu ekran görüntüsü App Switcher'da ve uygulamaya dönüşte (“çözülme” animasyonu olarak) gösterilir. Uygulama gizli veriler içeriyorsa, anlık görüntü bunları açığa çıkarabilir. Korumak için UIApplication.shouldSnapshotSecureApp (iOS 16+) kullanın veya applicationDidEnterBackground'da bir bulanıklık katmanı uygulayın.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun