In questo articolo analizzeremo il ciclo di vita delle applicazioni iOS, cioè tutto ciò che accade tra il loro lancio e la loro terminazione.
Vedremo esattamente che cosa succede dietro le quinte e scopriremo molte cose che ci aiuteranno a sviluppare applicazioni professionali e robuste.
Quali sono gli stati di un’applicazione?
Per prima cosa vediamo gli stati in cui si può trovare un’applicazione:

- Not Running: l’applicazione non è ancora stata lanciata, oppure è andata in crash o è stata terminata dal sistema operativo.
- Inactive: l’applicazione è in esecuzione in foreground, ma non sta ricevendo eventi. Potrebbe comunque eseguire del codice. L’applicazione si trova in questo stato durante la ricezione di una telefonata, di un SMS, quando il dispositivo è in lock o in generale quando compare una finestra in sovrimpressione (overlay window).
- Active: l’applicazione è in esecuzione in foreground e sta ricevendo eventi. Questo è lo stato “normale” in cui si trova l’applicazione quando ne vediamo l’interfaccia utente.
- Background: l’applicazione è in background e sta eseguendo del codice, ma non riceve eventi utente. Non essendo visibile, un’applicazione in background non deve aggiornare l’interfaccia grafica. Questo stato è disponibile solo a partire da iOS 4.0.
- Suspended: l’applicazione è in background ma non sta eseguendo codice, dunque è sostanzialmente “congelata” e non sta facendo in alcun modo uso della CPU. Se per qualunque motivo il sistema operativo necessita di liberare della memoria, le applicazioni che si trovano in questo stato potrebbero essere terminate (cioè poste nello stato Not Running) senza alcuna notifica e a completa discrezione del sistema. Questo stato è disponibile solo a partire da iOS 4.0.
Una ed una sola applicazione alla volta può essere in foreground, ovvero negli stati Active o Inactive.
Come avviene il passaggio tra i vari stati?
Il passaggio tra i diversi stati è regolato dal sistema in risposta agli eventi utente o a eventi di sistema (come la ricezione di una telefonata o di un SMS).
Supponiamo di aver appena fatto il reboot del nostro dispositivo. L’applicazione si trova nello stato Not Running perché non è ancora stata lanciata.
Quando premiamo sull’icona dell’applicazione nella Home Screen il sistema operativo carica l’immagine di apertura (Default.png) e poi lancia la funzione main(), entry point di ogni applicazione iOS, che tipicamente è composta da appena quattro istruzioni:

La funzione UIApplicationMain() è il vero cuore dell’applicazione, che si occupa di creare il singleton UIApplication, caricare il main NIB file e instanziare il delegato dell’applicazione.
Terminato il setup iniziale, l’applicazione passa nello stato Inactive e subito dopo viene chiamato il metodo application:didFinishLaunchingWithOptions: sul delegato dell’applicazione. (In generale, come vedremo meglio nel prossimo paragrafo, attraverso il delegato dell’applicazione possiamo essere informati delle transizioni tra i vari stati che un’applicazione può assumere durante il suo ciclo di vita.)
Dopo che il metodo application:didFinishLaunchingWithOptions: ha terminato la sua esecuzione viene avviato l’event loop, che riceve gli eventi (es: tap dell’utente sullo schermo) e si occupa di inviarli a chi li deve gestire. L’applicazione diventa quindi Active e può ricevere gli eventi e aggiornare l’interfaccia grafica. Nel passaggio dallo stato Inactive ad Active viene chiamato il metodo applicationDidBecomeActive: sul delegato dell’applicazione. L’applicazione è ora in esecuzione e l’utente può interagirvi.
Ecco una figura che riassume graficamente quanto abbiamo appena visto:

Ma che cosa succede quando l’utente preme sul tasto Home? A partire da iOS 4.0, l’applicazione torna prima nello stato Inactive (e dunque viene chiamato il metodo applicationWillResignActive: sul delegato dell’applicazione) e poi passa rapidamente nello stato Background. A questo punto viene chiamato sul delegato dell’applicazione il metodo applicationDidEnterBackground:, che possiamo usare per liberare eventuali risorse, salvare lo stato, chiudere le connessioni e così via. Infine l’applicazione passa allo stato Suspended in cui è sostanzialmente congelata.
Nello stato Suspended molti oggetti, inclusi i view controller, le view e gli altri oggetti da noi creati, rimangono in memoria. Tuttavia, il sistema rilascia alcuni degli oggetti usati dietro le quinte, tra cui i riferimenti alle immagini nella cache e alcuni oggetti usati da Core Animation.
Quando l’utente rilancia l’applicazione, ad esempio premendo sulla sua incona nella Home Screen o nella barra del multitasking, il sistema la sposta prima nello stato Inactive e poi rapidamente nello stato Active. Questo passaggio, per il fatto che l’applicazione era già congelata, è molto rapido, per questo Apple parla di fast app switching.
Come sono gestite le interruzioni?
Quando un’applicazione che si trova nello stato Active viene interrotta a causa della ricezione di una telefonata, di un SMS di un avviso di calendario, viene temporaneamente spostata nello stato Inactive. Rimarrà in questo stato fino a quando l’utente non decide di ignorare o accettare l’interruzione.
Se l’utente ignora l’interruzione, l’applicazione torna nello stato Active. Se invece accetta l’interruzione, l’applicazione viene spostata nello stato Background.
Terminata l’interruzione, in alcuni casi il sistema rilancia in automatico l’applicazione che si trovava in foreground. Capita, ad esempio, se l’utente riceve una chiamata e poi mette giù.
Come funziona il delegato dell’applicazione?
Attraverso il delegato dell’applicazione possiamo essere informati delle transizioni tra i vari stati che un’applicazione può assumere durante il suo ciclo di vita. In particolare, il delegato dell’applicazione (che viene creato per noi direttamente da Xcode e che implementa il protocollo UIApplicationDelegate) può implementare questi metodi:
- application:didFinishLaunchingWithOptions:. E’ il metodo che viene chiamato subito dopo che l’applicazione è stata lanciata, cioè nel passaggio da Not Running a Inactive. Dobbiamo usarlo per inizializzare la nostra applicazione e prepararla per l’esecuzione. Questo metodo ha circa 20 secondi per terminare.
- applicationWillResignActive:. E’ il metodo che viene chiamato appena prima del passaggio dallo stato Active a Inactive, ad esempio perché abbiamo ricevuto una telefonata o un SMS, oppure perché abbiamo messo il dispositivo in lock. Dobbiamo usarlo per disabilitare tutto ciò che ha a che fare con la presentazione grafica e l’interazione utente. Nel caso di un gioco, inoltre, possiamo usarlo per mettere il gioco in pausa.
- applicationDidBecomeActive:. E’ il metodo che viene chiamato subito dopo il passaggio dallo stato Inactive a Active. Dobbiamo usarlo per riabilitare tutto ciò che ha a che fare con la presentazione grafica e l’interazione utente.
- applicationDidEnterBackground:. E’ il metodo che viene chiamato non appena l’applicazione è entrata nello stato Background. Dobbiamo usarlo per salvare lo stato dell’applicazione, rilasciare tutte le risorse che possono essere ricreate in seguito, e così via. In tal modo riduciamo la memory footprint dell’applicazione e di conseguenza le possibilità che possa essere terminata dal sistema. Questo metodo ha circa 5 secondi per terminare.
- applicationWillEnterForeground:. E’ il metodo che viene chiamato appena prima del passaggio dallo stato Background a Inactive. Dobbiamo usarlo per ricreare tutto ciò che era stato rilasciato nell’applicationDidEnterBackground:.
- applicationWillTerminate:. E’ il metodo che su iOS 3.x o precedenti veniva chiamato quando l’utente usciva dall’applicazione. Su iOS 4.0 o superiori potrebbe essere chiamato quando l’applicazione è nello stato Background (non Suspendend) e il sistema necessita di terminarla per qualche motivo. Tuttavia è a discrezione del sistema operativo e non possiamo farci affidamento, per cui all’atto pratico ci conviene semplicemente ignorare questo metodo.
Ecco una figura che riassume quanto abbiamo visto:

Possiamo notare che le transizioni tra Background e Suspended avvengono senza che venga chiamato alcun metodo sul delegato. Stesso discorso quando l’applicazione è in background e l’utente la chiude dalla barra del multitasking (o quando, per mancanza di memoria, il sistema decide di terminarla). In questi casi il sistema operativo invia semplicemente un segnale SIGKILL che termina immediatamente il processo. Ecco perché è fondamentale salvare lo stato dell’applicazione nel metodo applicationDidEnterBackground:
Per completezza aggiungo che ad ogni metodo del delegato corrisponde una notifica, anche se nella pratica mi è capitato di usarle molto raramente. Ecco comunque l’elenco:
Metodo del delegato | Notifica corrispondente |
application:didFinishLaunchingWithOptions: | UIApplicationDidFinishLaunchingNotification |
applicationWillResignActive: | UIApplicationWillResignActiveNotification |
applicationDidBecomeActive: | UIApplicationDidBecomeActiveNotification |
applicationDidEnterBackground: | UIApplicationDidEnterBackgroundNotification |
applicationWillEnterForeground: | UIApplicationWillEnterForegroundNotification |
L’oggetto UIApplication dispone di una proprietà in sola lettura chiamata applicationState che ci restituisce lo stato dell’applicazione (Active, Inactive, etc.) e che ci permette di sperimentare con quanto ho descritto in questo articolo.
Che cosa rappresenta il parametro launchOptions del metodo application:didFinishLaunchingWithOptions:?
Un’applicazione può essere lanciata per rispondere ad uno specifico tipo di evento. Per esempio, può essere lanciata da un’altra applicazione, oppure in risposta ad una push notification locale o remota, oppure per aprire un file. In questi casi, il parametro launchOptions passato al metodo application:didFinishLaunchingWithOptions: fornisce maggiori dettagli sul motivo per cui l’applicazione è stata lanciata.
Se l’applicazione è stata lanciata direttamente dall’utente, launchOptions vale nil.
Conclusioni
In questo articolo abbiamo visto tutti gli stati in cui può trovarsi un’applicazione. Successivamente abbiamo analizzato tutte le possibili transizioni tra di essi, evidenziando il fatto che avvengono in risposta agli eventi utente o a eventi di sistema (come la ricezione di una telefonata o di un SMS). Alla maggior parte di queste transizioni corrisponde la chiamata di un metodo sul delegato dell’applicazione, in cui è importante fare alcune cose per garantire che la nostra applicazione sia robusta e professionale.
Bibliografia
iOS Application Programming Guide, un’ottima guida che illustra le basi della programmazione di applicazioni iOS.
UIApplicationDelegate Protocol Reference, la documentazione ufficiale del protocollo UIApplicationDelegate.
L’autore
Valerio Dutto. Ingegnere informatico con oltre 5 anni di esperienza nella realizzazione di software professionali. Dal 2009 si occupa a tempo pieno di sviluppo e formazione su piattaforme iOS e Mac OS X. Ha contribuito a oltre 15 applicazioni iPhone e iPad, alcune delle quali hanno ricevuto importanti riconoscimenti. Il suo sito Web è http://www.valeriodutto.com.
7 Responses to “L#017 – Il ciclo di vita delle applicazioni iOS”
8 Giugno 2011
danielebell’articolo!
8 Giugno 2011
The iOS Application Life Cycle | Valerio Dutto[…] can find it here. I hope you enjoy […]
8 Giugno 2011
EnricoRaga, ma la versione mobile del sito è sparita? Perche mi carica quella desktop? E lentissima!!!
12 Giugno 2011
Il ciclo di vita delle applicazioni iOS [devapp] « il mio lavoro… le mie passioni…[…] Potete leggere tutto l’articolo qui […]
14 Giugno 2011
dvddavima quindi il main va lasciato così com’è?
non serve a nulla aggiungerci parti del programma?
21 Ottobre 2011
The iOS Application Life Cycle | Delite Studio[…] Our article on the iOS Application Life Cycle (in italian) is now live on devApp.it website. […]
25 Giugno 2012
Alessandrouna domandina: quando termino una applicazione che eventi vengono richiamati ? ho l’impressione che vengano richiamati di nuovo gli stessi eventi di quando l’app passa in background, ma questa cosa non mi pare documentata. una curiosita’ sul CV : ma quali riconoscimenti hanno ricevuto le tue app ?