Background Task — mecanismul iOS care permite aplicației să finalizeze o operație începută după trecerea în modul fundal. Sistemul alocă timp limitat (până la 30 de secunde) pentru executarea sarcinii, după care aplicația este suspendată forțat. Conform Apple, 2026, utilizarea expiration handler este o cerință obligatorie pentru finalizarea corectă a sarcinii de fundal.
Principalele concluzii
Background Task este un mecanism software iOS care permite aplicației să prelungească timpul de execuție după trecerea în modul fundal. Când utilizatorul minimizează aplicația, sistemul apelează UIApplicationDelegate.applicationDidEnterBackground. Dacă în acel moment se execută o operație critică (salvare date, trimitere cerere), aplicația poate solicita timp suplimentar prin beginBackgroundTask.
Fără utilizarea Background Task, aplicația este suspendată forțat după 3–5 secunde de la trecerea în fundal. Toate operațiile neterminate sunt întrerupte: datele nu se salvează, cererile de rețea se întrerup, stările se pierd. Background Task oferă aplicației până la 30 de secunde pentru finalizarea corectă a acestor operații.
beginBackgroundTask a apărut în iOS 4.0 — prima versiune care suporta multitasking. Înainte de iOS 4, aplicația se închidea complet la apăsarea butonului Home. Din iOS 7 au apărut Background Fetch și URLSession background configuration. Începând cu iOS 13, Apple recomandă BGTaskScheduler pentru proiecte noi, dar beginBackgroundTask rămâne relevant pentru operații de scurtă durată.
beginBackgroundTask — metoda UIApplication care înregistrează o sarcină și returnează un identificator unic UIBackgroundTaskIdentifier. Sistemul mărește cronometrul de execuție în fundal. La expirarea timpului, este apelat expiration handler, după care aplicația trebuie să apeleze endBackgroundTask(identifier:) pentru finalizare corectă.
Pasul 1 — aplicația primește notificarea didEnterBackground. Pasul 2 — se apelează beginBackgroundTask(expirationHandler:). Pasul 3 — se execută operația critică (salvare, cerere de rețea). Pasul 4 — la finalizare se apelează endBackgroundTask(identifier:). Dacă operația nu se finalizează în 30 de secunde — sistemul apelează expiration handler, iar aplicația trebuie să încheie sarcina imediat.
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Expiration handler
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
func finishBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
Proprietatea backgroundTimeRemaining returnează numărul de secunde rămase până la finalizarea forțată a sarcinii de fundal. Valoarea scade în timp real. Dacă aplicația nu este în fundal — returnează DBL_MAX. Folosește această proprietate pentru a adapta comportamentul: când rămân mai puțin de 5 secunde, întrerupe operațiile lungi și salvează progresul.
Aplicația poate înregistra mai multe Background Task simultan. Fiecare sarcină primește propriul identificator. Timpul total de execuție se însumează — dacă sunt înregistrate 3 sarcini, aplicația poate primi până la 90 de secunde. Totuși, sistemul poate termina aplicația mai devreme dacă resursele sunt epuizate sau limita bateriei este depășită.
Expiration handler este un bloc de cod apelat de sistem la expirarea timpului alocat pentru sarcina de fundal. Prezența expiration handler este o cerință obligatorie Apple. Fără el, aplicația poate fi terminată forțat de sistem, iar datele pot fi pierdute.
Expiration handler trebuie să efectueze acțiuni minime pentru salvarea stării aplicației: să salveze datele curente în stocare persistentă, să apeleze endBackgroundTask cu identificatorul corespunzător și să seteze identificatorul la .invalid. În interiorul expiration handler este interzisă pornirea de noi operații lungi — timpul de execuție este limitat la 1–2 secunde.
func handleExpiration() {
// Salvăm progresul execuției
saveProgressToUserDefaults()
// Anulăm cererile de rețea active
currentTask?.cancel()
// Finalizăm Background Task
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// Înregistrare cu expiration handler
backgroundTaskID = UIApplication.shared.beginBackgroundTask(
withName: "SaveDocument",
expirationHandler: handleExpiration
)
Cea mai frecventă eroare este neapelarea endBackgroundTask în interiorul expiration handler. În acest caz, sistemul continuă să considere sarcina activă, aplicația nu trece în starea Suspended, iar bateria se descarcă. A doua eroare este pornirea de operații lungi în interiorul expiration handler. Sistemul poate termina aplicația înainte de finalizarea lor, iar datele se pierd.
În expiration handler, timpul de execuție este critic de scurt — de obicei mai puțin de 1 secundă. Prin urmare, în interiorul handler nu se pot executa: calcule complexe, cereri de rețea, scrierea de volume mari de date în CoreData. Doar operații atomice: scrierea unei chei în UserDefaults, setarea unui indicator de stare, apelarea endBackgroundTask.
Să analizăm implementarea completă a Background Task pentru salvarea unui document la trecerea aplicației în fundal. Exemplul include înregistrarea sarcinii, executarea operației cu verificarea timpului rămas și finalizarea corectă prin endBackgroundTask.
La trecerea în fundal, aplicația inițiază salvarea unui document mare. Background Task oferă până la 30 de secunde pentru operație. Dacă timpul expiră — expiration handler salvează rezultatele intermediare. După finalizarea salvării, se apelează endBackgroundTask pentru eliberarea resurselor.
class DocumentManager {
private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func saveDocumentInBackground(document: Document) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
self.saveProgress(document)
self.endBackgroundTask()
}
DispatchQueue.global().async {
document.save()
self.endBackgroundTask()
}
}
private func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
Cererile de rețea în fundal necesită atenție specială — expiration handler poate întrerupe cererea înainte de primirea răspunsului. Folosește URLSession cu dataTask și verifică backgroundTimeRemaining înainte de trimitere. Dacă au rămas mai puțin de 5 secunde — amână trimiterea până la următoarea reactivare a aplicației.
func sendCriticalData(data: Data) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Salvăm datele pentru retrimitere
saveForRetry(data)
self.endBackgroundTask()
}
let task = URLSession.shared.dataTask(with: request) { _, _, error in
if error != nil {
saveForRetry(data)
}
self.endBackgroundTask()
}
task.resume()
}
Pentru operații lungi, urmărește UIApplication.shared.backgroundTimeRemaining. Dacă valoarea scade sub prag (10 secunde), întrerupe operația curentă și pornește salvarea rezultatelor intermediare. Acest lucru permite finalizarea corectă a lucrului înainte de apelarea forțată a expiration handler.
Background Task este un mecanism puternic, dar utilizarea sa incorectă duce la probleme cu bateria și performanța. Respectarea recomandărilor Apple și a practicilor verificate ale comunității ajută la evitarea erorilor tipice și asigurarea funcționării stabile a aplicației.
Finalizează Background Task cât mai rapid posibil. Fiecare secundă de execuție în fundal consumă energie din baterie. Timpul optim — sub 5 secunde. Dacă operația durează mai mult — ia în considerare utilizarea BGTaskScheduler sau Background Modes. Nu prelungi sarcina artificial prin apeluri beginBackgroundTask fără necesitate reală.
Stochează UIBackgroundTaskIdentifier ca proprietate a clasei sau structurii. Nu îl transmite niciodată ca variabilă globală — acest lucru duce la conflicte la sarcini multiple. Setează identificatorul la .invalid după apelarea endBackgroundTask pentru a preveni dubla finalizare.
În Xcode Simulator comută aplicația în fundal prin butonul Home (Command + Shift + H). Folosește Debug — Simulate Background Fetch pentru testarea reactivării în fundal. Pentru a simula expirarea timpului, setează variabila de mediu BACKGROUND_TASK_SIMULATE_EXPIRATION = YES — expiration handler va fi apelat după 5 secunde.
// Verificarea timpului rămas înainte de începerea operației
let remaining = UIApplication.shared.backgroundTimeRemaining
guard remaining > 10.0 else {
// Timp insuficient — amână sarcina
scheduleForNextLaunch()
return
}
// Executarea operației cu controlul timpului
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
saveProgress()
self.endBackgroundTask()
}
Expiration handler capturează self — acest lucru poate crea un retain cycle dacă backgroundTaskID este stocat ca proprietate a aceluiași obiect. Folosește [weak self] în închidere sau stochează identificatorul separat. Retain cycle duce la scurgeri de memorie — obiectul nu va fi eliberat până la terminarea aplicației.
Odată cu lansarea iOS 13, Apple a introdus BGTaskScheduler — un înlocuitor modern pentru vechiul API Background Task. Ambele mecanisme rezolvă sarcini similare, dar BGTaskScheduler oferă mai mult control și flexibilitate. Înțelegerea diferențelor ajută la alegerea instrumentului potrivit pentru scenariul specific.
| Caracteristică | Background Task | BGTaskScheduler |
|---|---|---|
| Versiune iOS | 4.0+ | 13.0+ |
| Timp maxim | 30 de secunde | 30 s / 10 min (processing) |
| Inițiere | didEnterBackground | Planificare + sistem |
| Garanție execuție | Doar la trecerea în fundal | În orice moment convenabil pentru sistem |
| Expiration handler | Da, obligatoriu | Da, prin task.expirationHandler |
| Internet | Necesar la pornire | Disponibil prin requiresNetworkConnectivity |
| Încărcare | Nu este necesară | Opțional pentru processing |
beginBackgroundTask este potrivit pentru operații de scurtă durată care trebuie executate imediat la trecerea în fundal: salvare stare, finalizare cerere de rețea, cache de date. API-ul este simplu și nu necesită configurare Info.plist sau înregistrare de identificatori. Ideal pentru operații care durează mai puțin de 10 secunde.
BGTaskScheduler este potrivit pentru sarcini care pot fi executate în orice moment convenabil: sincronizare periodică, curățare cache, actualizare widgeturi. Sistemul alege singur momentul optim ținând cont de comportamentul utilizatorului și starea bateriei. Pentru operații lungi (până la 10 minute) folosește BGProcessingTask.
Ambele API pot fi folosite în aceeași aplicație. Background Task — pentru operații imediate la trecerea în fundal (salvare ciornă). BGTaskScheduler — pentru actualizări planificate (sincronizare la fiecare 6 ore). Împărțirea responsabilităților permite garantarea salvării corecte a datelor și a serviciului de fundal eficient energetic.
Întrebări frecvente
Da, beginBackgroundTask poate fi apelat în orice moment al funcționării aplicației. Totuși, alocarea de timp de către sistem va începe doar după trecerea în fundal. Dacă aplicația este în prim-plan, apelul beginBackgroundTask nu are efect — backgroundTimeRemaining returnează DBL_MAX, iar sarcina va fi activată la trecerea în fundal.
Dacă nu se apelează endBackgroundTask, sistemul continuă să considere aplicația activă în fundal. După 30 de secunde va fi apelat expiration handler, dar dacă nici în el nu există endBackgroundTask — aplicația rămâne în memorie, consumând baterie. În iOS 13+ sistemul termină forțat o astfel de aplicație după 3 minute.
Timpul standard este de 30 de secunde. Se poate prelungi doar prin Background Modes: Audio (redare), Location (geolocație), Bluetooth (BLE). Sau prin BGProcessingTask (iOS 13+) — până la 10 minute cu condiția încărcării și Wi-Fi. beginBackgroundTask în sine nu oferă nicio modalitate de a mări limita.
Da, iPadOS suportă complet beginBackgroundTask cu aceleași limitări ca iOS. Pe iPad cu Stage Manager, aplicația poate rămâne în memorie mai mult timp — sistemul suspendă aplicațiile mai rar datorită cantității mai mari de RAM. Dar limita de 30 de secunde pentru sarcina de fundal rămâne.
Conectează dispozitivul la Xcode, pornește aplicația, minimizeaz-o — în consolă vor apărea logurile sistemului. Folosește sysdiagnose pentru colectarea de loguri detaliate: declanșează sysdiagnose de pe dispozitiv (Volume Up + Down + Power). În Xcode Debug Navigator urmărește activitatea sarcinilor de fundal.
Rezumat
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.
Citiți și