Background Task è un meccanismo iOS che consente a un'applicazione di completare un'operazione dopo il passaggio in background. Il sistema alloca un tempo limitato (fino a 30 secondi) per eseguire l'attività, dopodiché l'applicazione viene sospesa forzatamente. Secondo Apple, 2026, l'uso di un expiration handler è un requisito obbligatorio per completare correttamente un'attività in background.
Punti chiave
Background Task è un meccanismo programmatico iOS che consente a un'applicazione di estendere il tempo di esecuzione dopo il passaggio in background. Quando l'utente minimizza l'app, il sistema chiama UIApplicationDelegate.applicationDidEnterBackground. Se in quel momento è in esecuzione un'operazione critica (salvataggio dati, invio di una richiesta), l'applicazione può richiedere tempo aggiuntivo tramite beginBackgroundTask.
Senza utilizzare Background Task, l'applicazione viene sospesa forzatamente entro 3–5 secondi dal passaggio in background. Tutte le operazioni incomplete vengono interrotte: i dati non vengono salvati, le richieste di rete vengono abortite, gli stati vengono persi. Background Task concede all'applicazione fino a 30 secondi per completare correttamente queste operazioni.
beginBackgroundTask è apparso in iOS 4.0 — la prima versione con supporto multitasking. Prima di iOS 4, l'applicazione veniva terminata completamente premendo il pulsante Home. iOS 7 ha introdotto Background Fetch e la configurazione in background di URLSession. A partire da iOS 13, Apple raccomanda BGTaskScheduler per i nuovi progetti, ma beginBackgroundTask rimane rilevante per le operazioni a breve termine.
beginBackgroundTask è un metodo di UIApplication che registra un'attività e restituisce un identificatore univoco UIBackgroundTaskIdentifier. Il sistema aumenta il timer di esecuzione in background. Quando il tempo scade, viene chiamato l'expiration handler, dopodiché l'applicazione deve chiamare endBackgroundTask(identifier:) per completare correttamente l'attività.
Passo 1 — l'applicazione riceve la notifica didEnterBackground. Passo 2 — viene chiamato beginBackgroundTask(expirationHandler:). Passo 3 — viene eseguita l'operazione critica (salvataggio, richiesta di rete). Passo 4 — al completamento, viene chiamato endBackgroundTask(identifier:). Se l'operazione non viene completata entro 30 secondi — il sistema chiama l'expiration handler e l'applicazione deve terminare immediatamente l'attività.
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
}
La proprietà backgroundTimeRemaining restituisce il numero di secondi rimanenti prima che l'attività in background venga terminata forzatamente. Il valore diminuisce in tempo reale. Se l'applicazione non è in background — restituisce DBL_MAX. Utilizza questa proprietà per adattare il comportamento: quando rimangono meno di 5 secondi, interrompi le operazioni lunghe e salva i progressi.
Un'applicazione può registrare più Background Tasks contemporaneamente. Ogni attività riceve il proprio identificatore. Il tempo totale di esecuzione è cumulativo — se vengono registrate 3 attività, l'applicazione può ottenere fino a 90 secondi. Tuttavia, il sistema può terminare l'applicazione prima se le risorse sono esaurite o il limite della batteria è stato superato.
Expiration handler è un blocco di codice che il sistema chiama quando il tempo allocato per l'attività in background scade. Avere un expiration handler è un requisito obbligatorio di Apple. Senza di esso, l'applicazione può essere terminata forzatamente dal sistema e i dati possono essere persi.
L'expiration handler deve eseguire azioni minime per salvare lo stato dell'applicazione: salvare i dati correnti nell'archivio persistente, chiamare endBackgroundTask con l'identificatore corrispondente e impostare l'identificatore su .invalid. All'interno dell'expiration handler è vietato avviare nuove operazioni lunghe — il tempo di esecuzione è limitato a 1–2 secondi.
func handleExpiration() {
// Salvataggio dell'avanzamento dell'esecuzione
saveProgressToUserDefaults()
// Annullamento delle richieste di rete attive
currentTask?.cancel()
// Chiusura di Background Task
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// Registrazione con expiration handler
backgroundTaskID = UIApplication.shared.beginBackgroundTask(
withName: "SaveDocument",
expirationHandler: handleExpiration
)
L'errore più comune è non chiamare endBackgroundTask all'interno dell'expiration handler. In questo caso, il sistema continua a considerare l'attività attiva, l'applicazione non passa allo stato Sospeso e la batteria si scarica. Il secondo errore è avviare operazioni lunghe all'interno dell'expiration handler. Il sistema può terminare l'applicazione prima che vengano completate e i dati andranno persi.
Nell'expiration handler, il tempo di esecuzione è criticamente limitato — tipicamente meno di 1 secondo. Pertanto, all'interno dell'handler non è possibile eseguire: calcoli complessi, richieste di rete, scrittura di grandi volumi di dati in CoreData. Solo operazioni atomiche: scrivere una singola chiave in UserDefaults, impostare un flag di stato, chiamare endBackgroundTask.
Esaminiamo un'implementazione completa di Background Task per salvare un documento quando l'app va in background. L'esempio include la registrazione dell'attività, l'esecuzione dell'operazione con verifica del tempo rimanente e il corretto completamento tramite endBackgroundTask.
Quando va in background, l'applicazione avvia il salvataggio di un documento grande. Background Task fornisce fino a 30 secondi per l'operazione. Se il tempo scade — l'expiration handler salva i risultati intermedi. Dopo il completamento del salvataggio, viene chiamato endBackgroundTask per liberare le risorse.
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
}
}
Le richieste di rete in background richiedono attenzione speciale — l'expiration handler può interrompere la richiesta prima di ricevere una risposta. Utilizza URLSession con dataTask e verifica backgroundTimeRemaining prima di inviare. Se rimangono meno di 5 secondi — rimanda l'invio fino al prossimo ripristino dell'app.
func sendCriticalData(data: Data) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Salvataggio dei dati per il reinvio
saveForRetry(data)
self.endBackgroundTask()
}
let task = URLSession.shared.dataTask(with: request) { _, _, error in
if error != nil {
saveForRetry(data)
}
self.endBackgroundTask()
}
task.resume()
}
Per le operazioni lunghe, monitora UIApplication.shared.backgroundTimeRemaining. Se il valore scende al di sotto di una soglia (10 secondi), interrompi l'operazione corrente e inizia a salvare i risultati intermedi. Ciò consente un corretto completamento prima che l'expiration handler venga chiamato forzatamente.
Background Task è un potente meccanismo, ma il suo uso improprio porta a problemi di batteria e prestazioni. Seguire le raccomandazioni di Apple e le pratiche comprovate della comunità aiuterà a evitare errori comuni e garantire un funzionamento stabile dell'applicazione.
Completa la Background Task il più rapidamente possibile. Ogni secondo di esecuzione in background consuma batteria. Tempo ottimale — meno di 5 secondi. Se l'operazione richiede più tempo — considera l'uso di BGTaskScheduler o Background Modes. Non prolungare artificialmente l'attività tramite chiamate beginBackgroundTask senza reale necessità.
Archivia UIBackgroundTaskIdentifier come proprietà di una classe o struttura. Non passarlo mai come variabile globale — questo porta a conflitti con attività multiple. Imposta l'identificatore su .invalid dopo aver chiamato endBackgroundTask per prevenire il doppio completamento.
Nel Simulatore Xcode, passa l'applicazione in background tramite il pulsante Home (Comando + Shift + H). Utilizza Debug — Simulate Background Fetch per testare il risveglio in background. Per simulare la scadenza del tempo, imposta la Variabile d'ambiente BACKGROUND_TASK_SIMULATE_EXPIRATION = YES — l'expiration handler verrà chiamato entro 5 secondi.
// Verifica del tempo rimanente prima di iniziare l'operazione
let remaining = UIApplication.shared.backgroundTimeRemaining
guard remaining > 10.0 else {
// Tempo insufficiente — posticipare l'attività
scheduleForNextLaunch()
return
}
// Esecuzione dell'operazione con controllo del tempo
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
saveProgress()
self.endBackgroundTask()
}
L'expiration handler cattura self — questo può creare un retain cycle se backgroundTaskID è archiviato come proprietà dello stesso oggetto. Utilizza [weak self] nella closure o archivia l'identificatore separatamente. Un retain cycle porta a una perdita di memoria — l'oggetto non verrà rilasciato fino alla terminazione dell'applicazione.
Con il rilascio di iOS 13, Apple ha presentato BGTaskScheduler — un moderno sostituto della vecchia API Background Task. Entrambi i meccanismi risolvono attività simili, ma BGTaskScheduler offre maggiore controllo e flessibilità. Comprendere le differenze aiuterà a scegliere lo strumento giusto per uno scenario specifico.
| Caratteristica | Background Task | BGTaskScheduler |
|---|---|---|
| Versione iOS | 4.0+ | 13.0+ |
| Tempo massimo | 30 secondi | 30 s / 10 min (processing) |
| Iniziazione | didEnterBackground | Pianificazione + sistema |
| Garanzia di esecuzione | Solo quando si va in background | In qualsiasi momento conveniente per il sistema |
| Expiration handler | Sì, obbligatorio | Sì, tramite task.expirationHandler |
| Internet | Richiesto all'avvio | Disponibile tramite requiresNetworkConnectivity |
| Carica | Non richiesto | Opzionale per processing |
beginBackgroundTask è adatto per operazioni a breve termine che devono essere eseguite immediatamente quando si va in background: salvataggio dello stato, completamento di una richiesta di rete, caching dei dati. L'API è semplice e non richiede configurazione Info.plist o registrazione di identificatori. Ideale per operazioni che richiedono meno di 10 secondi.
BGTaskScheduler è adatto per attività che possono essere eseguite in qualsiasi momento conveniente: sincronizzazione periodica, pulizia della cache, aggiornamento dei widget. Il sistema stesso seleziona il momento ottimale considerando il comportamento dell'utente e lo stato della batteria. Per operazioni lunghe (fino a 10 minuti), utilizza BGProcessingTask.
Entrambe le API possono essere utilizzate nella stessa applicazione. Background Task — per operazioni immediate quando si va in background (salvare una bozza). BGTaskScheduler — per aggiornamenti pianificati (sincronizzazione ogni 6 ore). La separazione delle responsabilità garantisce la corretta conservazione dei dati e una manutenzione in background efficiente dal punto di vista energetico.
Domande frequenti
Sì, beginBackgroundTask può essere chiamato in qualsiasi momento durante l'esecuzione dell'applicazione. Tuttavia, l'allocazione del tempo di sistema inizierà solo dopo il passaggio in background. Se l'applicazione è in primo piano, chiamare beginBackgroundTask non ha effetto — backgroundTimeRemaining restituisce DBL_MAX e l'attività verrà attivata quando si va in background.
Se endBackgroundTask non viene chiamato, il sistema continua a considerare l'applicazione attiva in background. Dopo 30 secondi, l'expiration handler verrà chiamato, ma se anche questo manca di endBackgroundTask — l'applicazione rimane in memoria, scaricando la batteria. In iOS 13+, il sistema termina forzatamente tale applicazione dopo 3 minuti.
Il tempo standard è di 30 secondi. Può essere esteso solo tramite Background Modes: Audio (riproduzione), Posizione (geolocalizzazione), Bluetooth (BLE). O tramite BGProcessingTask (iOS 13+) — fino a 10 minuti con carica e Wi-Fi. beginBackgroundTask stesso non fornisce un modo per aumentare il limite.
Sì, iPadOS supporta completamente beginBackgroundTask con le stesse limitazioni di iOS. Su iPad con Stage Manager, l'applicazione può rimanere più a lungo in memoria — il sistema sospende le applicazioni meno frequentemente a causa della maggiore RAM. Ma il limite di 30 secondi per le attività in background rimane.
Collega il dispositivo a Xcode, avvia l'applicazione, minimizzala — i log di sistema appariranno nella console. Utilizza sysdiagnose per raccogliere log dettagliati: attiva forzatamente sysdiagnose dal dispositivo (Volume Su + Volume Giù + Accensione). Nel Debug Navigator di Xcode, monitora l'attività delle attività in background.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche