{"id":7032,"date":"2011-06-08T09:30:11","date_gmt":"2011-06-08T07:30:11","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=7032"},"modified":"2011-06-08T09:40:49","modified_gmt":"2011-06-08T07:40:49","slug":"l017-il-ciclo-di-vita-delle-applicazioni-ios","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/l017-il-ciclo-di-vita-delle-applicazioni-ios\/","title":{"rendered":"L#017 &#8211; Il ciclo di vita delle applicazioni iOS"},"content":{"rendered":"<p>In questo articolo analizzeremo il ciclo di vita delle applicazioni iOS, cio\u00e8 tutto ci\u00f2 che accade tra il loro lancio e la loro terminazione.<\/p>\n<p>Vedremo esattamente che cosa succede dietro le quinte e scopriremo molte cose che ci aiuteranno a sviluppare applicazioni professionali e robuste.<!--more--><\/p>\n<h4>Quali sono gli stati di un&#8217;applicazione?<\/h4>\n<p>Per prima cosa vediamo gli stati in cui si pu\u00f2 trovare un&#8217;applicazione:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-01.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-01.png\" alt=\"Ciclo-di-vita-applicazioni-iOS-01\" title=\"Ciclo-di-vita-applicazioni-iOS-01\" width=\"500\" height=\"503\" class=\"aligncenter size-full wp-image-7035\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-01.png 500w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-01-150x150.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-01-298x300.png 298w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-01-64x64.png 64w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/a><br \/>\n<\/center><\/p>\n<ul>\n<li><strong>Not Running<\/strong>: l&#8217;applicazione non \u00e8 ancora stata lanciata, oppure \u00e8 andata in crash o \u00e8 stata terminata dal sistema operativo.<\/li>\n<li><strong>Inactive<\/strong>: l&#8217;applicazione \u00e8 in esecuzione in foreground, ma non sta ricevendo eventi. Potrebbe comunque eseguire del codice. L&#8217;applicazione si trova in questo stato durante la ricezione di una telefonata, di un SMS, quando il dispositivo \u00e8 in lock o in generale quando compare una finestra in sovrimpressione (overlay window).<\/li>\n<li><strong>Active<\/strong>: l&#8217;applicazione \u00e8 in esecuzione in foreground e sta ricevendo eventi. Questo \u00e8 lo stato &#8220;normale&#8221; in cui si trova l&#8217;applicazione quando ne vediamo l&#8217;interfaccia utente.<\/li>\n<li><strong>Background<\/strong>: l&#8217;applicazione \u00e8 in background e sta eseguendo del codice, ma non riceve eventi utente. Non essendo visibile, un&#8217;applicazione in background non deve aggiornare l&#8217;interfaccia grafica. Questo stato \u00e8 disponibile solo a partire da iOS 4.0.<\/li>\n<li><strong>Suspended<\/strong>: l&#8217;applicazione \u00e8 in background ma non sta eseguendo codice, dunque \u00e8 sostanzialmente &#8220;congelata&#8221; 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\u00e8 poste nello stato Not Running) senza alcuna notifica e a completa discrezione del sistema. Questo stato \u00e8 disponibile solo a partire da iOS 4.0.<\/li>\n<\/ul>\n<p>Una ed una sola applicazione alla volta pu\u00f2 essere in foreground, ovvero negli stati Active o Inactive.<\/p>\n<h4>Come avviene il passaggio tra i vari stati?<\/h4>\n<p>Il passaggio tra i diversi stati \u00e8 regolato dal sistema in risposta agli eventi utente o a eventi di sistema (come la ricezione di una telefonata o di un SMS).<\/p>\n<p>Supponiamo di aver appena fatto il reboot del nostro dispositivo. L&#8217;applicazione si trova nello stato <strong>Not Running<\/strong> perch\u00e9 non \u00e8 ancora stata lanciata.<\/p>\n<p>Quando premiamo sull&#8217;icona dell&#8217;applicazione nella Home Screen il sistema operativo carica l&#8217;immagine di apertura (Default.png) e poi lancia la funzione main(), entry point di ogni applicazione iOS, che tipicamente \u00e8 composta da appena quattro istruzioni:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-02.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-02.png\" alt=\"Ciclo-di-vita-applicazioni-iOS-02\" title=\"Ciclo-di-vita-applicazioni-iOS-02\" width=\"491\" height=\"117\" class=\"aligncenter size-full wp-image-7036\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-02.png 491w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-02-300x71.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-02-150x35.png 150w\" sizes=\"auto, (max-width: 491px) 100vw, 491px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>La funzione UIApplicationMain() \u00e8 il vero cuore dell&#8217;applicazione, che si occupa di creare il singleton UIApplication, caricare il main NIB file e instanziare il delegato dell&#8217;applicazione.<\/p>\n<p>Terminato il setup iniziale, l&#8217;applicazione passa nello stato <strong>Inactive<\/strong> e subito dopo viene chiamato il metodo application:didFinishLaunchingWithOptions: sul delegato dell&#8217;applicazione. (In generale, come vedremo meglio nel prossimo paragrafo, attraverso il delegato dell&#8217;applicazione possiamo essere informati delle transizioni tra i vari stati che un&#8217;applicazione pu\u00f2 assumere durante il suo ciclo di vita.)<\/p>\n<p>Dopo che il metodo application:didFinishLaunchingWithOptions: ha terminato la sua esecuzione viene avviato l&#8217;event loop, che riceve gli eventi (es: tap dell&#8217;utente sullo schermo) e si occupa di inviarli a chi li deve gestire. L&#8217;applicazione diventa quindi <strong>Active<\/strong> e pu\u00f2 ricevere gli eventi e aggiornare l&#8217;interfaccia grafica. Nel passaggio dallo stato Inactive ad Active viene chiamato il metodo applicationDidBecomeActive: sul delegato dell&#8217;applicazione. L&#8217;applicazione \u00e8 ora in esecuzione e l&#8217;utente pu\u00f2 interagirvi.<\/p>\n<p>Ecco una figura che riassume graficamente quanto abbiamo appena visto:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-03.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-03.png\" alt=\"Ciclo-di-vita-applicazioni-iOS-03\" title=\"Ciclo-di-vita-applicazioni-iOS-03\" width=\"550\" height=\"367\" class=\"aligncenter size-full wp-image-7037\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-03.png 550w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-03-300x200.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-03-150x100.png 150w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Ma che cosa succede quando l&#8217;utente preme sul tasto Home? A partire da iOS 4.0, l&#8217;applicazione torna prima nello stato <strong>Inactive<\/strong> (e dunque viene chiamato il metodo applicationWillResignActive: sul delegato dell&#8217;applicazione) e poi passa rapidamente nello stato <strong>Background<\/strong>. A questo punto viene chiamato sul delegato dell&#8217;applicazione il metodo applicationDidEnterBackground:, che possiamo usare per liberare eventuali risorse, salvare lo stato, chiudere le connessioni e cos\u00ec via. Infine l&#8217;applicazione passa allo stato <strong>Suspended<\/strong> in cui \u00e8 sostanzialmente congelata.<\/p>\n<p>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.<\/p>\n<p>Quando l&#8217;utente rilancia l&#8217;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&#8217;applicazione era gi\u00e0 congelata, \u00e8 molto rapido, per questo Apple parla di fast app switching.<\/p>\n<h4>Come sono gestite le interruzioni?<\/h4>\n<p>Quando un&#8217;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\u00e0 in questo stato fino a quando l&#8217;utente non decide di ignorare o accettare l&#8217;interruzione.<\/p>\n<p>Se l&#8217;utente ignora l&#8217;interruzione, l&#8217;applicazione torna nello stato Active. Se invece accetta l&#8217;interruzione, l&#8217;applicazione viene spostata nello stato Background.<\/p>\n<p>Terminata l&#8217;interruzione, in alcuni casi il sistema rilancia in automatico l&#8217;applicazione che si trovava in foreground. Capita, ad esempio, se l&#8217;utente riceve una chiamata e poi mette gi\u00f9.<\/p>\n<h4>Come funziona il delegato dell&#8217;applicazione?<\/h4>\n<p>Attraverso il delegato dell&#8217;applicazione possiamo essere informati delle transizioni tra i vari stati che un&#8217;applicazione pu\u00f2 assumere durante il suo ciclo di vita. In particolare, il delegato dell&#8217;applicazione (che viene creato per noi direttamente da Xcode e che implementa il protocollo UIApplicationDelegate) pu\u00f2 implementare questi metodi:<\/p>\n<ul>\n<li><strong>application:didFinishLaunchingWithOptions:<\/strong>. E&#8217; il metodo che viene chiamato subito dopo che l&#8217;applicazione \u00e8 stata lanciata, cio\u00e8 nel passaggio da Not Running a Inactive. Dobbiamo usarlo per inizializzare la nostra applicazione e prepararla per l&#8217;esecuzione. Questo metodo ha circa 20 secondi per terminare.<\/li>\n<li><strong>applicationWillResignActive:<\/strong>. E&#8217; il metodo che viene chiamato appena prima del passaggio dallo stato Active a Inactive, ad esempio perch\u00e9 abbiamo ricevuto una telefonata o un SMS, oppure perch\u00e9 abbiamo messo il dispositivo in lock. Dobbiamo usarlo per disabilitare tutto ci\u00f2 che ha a che fare con la presentazione grafica e l&#8217;interazione utente. Nel caso di un gioco, inoltre, possiamo usarlo per mettere il gioco in pausa.<\/li>\n<li><strong>applicationDidBecomeActive:<\/strong>. E&#8217; il metodo che viene chiamato subito dopo il passaggio dallo stato Inactive a Active. Dobbiamo usarlo per riabilitare tutto ci\u00f2 che ha a che fare con la presentazione grafica e l&#8217;interazione utente.<\/li>\n<li><strong>applicationDidEnterBackground:<\/strong>. E&#8217; il metodo che viene chiamato non appena l&#8217;applicazione \u00e8 entrata nello stato Background. Dobbiamo usarlo per salvare lo stato dell&#8217;applicazione, rilasciare tutte le risorse che possono essere ricreate in seguito, e cos\u00ec via. In tal modo riduciamo la memory footprint dell&#8217;applicazione e di conseguenza le possibilit\u00e0 che possa essere terminata dal sistema. Questo metodo ha circa 5 secondi per terminare.<\/li>\n<li><strong>applicationWillEnterForeground:<\/strong>. E&#8217; il metodo che viene chiamato appena prima del passaggio dallo stato Background a Inactive. Dobbiamo usarlo per ricreare tutto ci\u00f2 che era stato rilasciato nell&#8217;applicationDidEnterBackground:.<\/li>\n<li><strong>applicationWillTerminate:<\/strong>. E&#8217; il metodo che su iOS 3.x o precedenti veniva chiamato quando l&#8217;utente usciva dall&#8217;applicazione. Su iOS 4.0 o superiori potrebbe essere chiamato quando l&#8217;applicazione \u00e8 nello stato Background (non Suspendend) e il sistema necessita di terminarla per qualche motivo. Tuttavia \u00e8 a discrezione del sistema operativo e non possiamo farci affidamento, per cui all&#8217;atto pratico ci conviene semplicemente ignorare questo metodo.<\/li>\n<\/ul>\n<p>Ecco una figura che riassume quanto abbiamo visto:<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-04.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-04.png\" alt=\"Ciclo-di-vita-applicazioni-iOS-04\" title=\"Ciclo-di-vita-applicazioni-iOS-04\" width=\"500\" height=\"477\" class=\"aligncenter size-full wp-image-7038\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-04.png 500w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-04-300x286.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/06\/Ciclo-di-vita-applicazioni-iOS-04-150x143.png 150w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Possiamo notare che le transizioni tra Background e Suspended avvengono senza che venga chiamato alcun metodo sul delegato. Stesso discorso quando l&#8217;applicazione \u00e8 in background e l&#8217;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\u00e9 \u00e8 fondamentale salvare lo stato dell&#8217;applicazione nel metodo applicationDidEnterBackground:<\/p>\n<p>Per completezza aggiungo che ad ogni metodo del delegato corrisponde una notifica, anche se nella pratica mi \u00e8 capitato di usarle molto raramente. Ecco comunque l&#8217;elenco:<\/p>\n<p><center><\/p>\n<table>\n<tr>\n<td><strong>Metodo del delegato<\/strong><\/td>\n<td><strong>Notifica corrispondente<\/strong><\/td>\n<\/tr>\n<tr>\n<td>application:didFinishLaunchingWithOptions:<\/td>\n<td>UIApplicationDidFinishLaunchingNotification<\/td>\n<\/tr>\n<tr>\n<td>applicationWillResignActive:<\/td>\n<td>UIApplicationWillResignActiveNotification<\/td>\n<\/tr>\n<tr>\n<td>applicationDidBecomeActive:<\/td>\n<td>UIApplicationDidBecomeActiveNotification<\/td>\n<\/tr>\n<tr>\n<td>applicationDidEnterBackground:<\/td>\n<td>UIApplicationDidEnterBackgroundNotification<\/td>\n<\/tr>\n<tr>\n<td>applicationWillEnterForeground:<\/td>\n<td>UIApplicationWillEnterForegroundNotification<\/td>\n<\/tr>\n<\/table>\n<p><\/center><\/p>\n<p>L&#8217;oggetto UIApplication dispone di una propriet\u00e0 in sola lettura chiamata applicationState che ci restituisce lo stato dell&#8217;applicazione (Active, Inactive, etc.) e che ci permette di sperimentare con quanto ho descritto in questo articolo.<\/p>\n<h4>Che cosa rappresenta il parametro launchOptions del metodo application:didFinishLaunchingWithOptions:?<\/h4>\n<p>Un&#8217;applicazione pu\u00f2 essere lanciata per rispondere ad uno specifico tipo di evento. Per esempio, pu\u00f2 essere lanciata da un&#8217;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&#8217;applicazione \u00e8 stata lanciata.<\/p>\n<p>Se l&#8217;applicazione \u00e8 stata lanciata direttamente dall&#8217;utente, launchOptions vale nil.<\/p>\n<h4>Conclusioni<\/h4>\n<p>In questo articolo abbiamo visto tutti gli stati in cui pu\u00f2 trovarsi un&#8217;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&#8217;applicazione, in cui \u00e8 importante fare alcune cose per garantire che la nostra applicazione sia robusta e professionale.<\/p>\n<h4>Bibliografia<\/h4>\n<p><a href=\"http:\/\/developer.apple.com\/library\/ios\/#DOCUMENTATION\/iPhone\/Conceptual\/iPhoneOSProgrammingGuide\/Introduction\/Introduction.html\" target=\"_blank\">iOS Application Programming Guide<\/a>, un&#8217;ottima guida che illustra le basi della programmazione di applicazioni iOS.<\/p>\n<p><a href=\"http:\/\/developer.apple.com\/library\/ios\/#documentation\/uikit\/reference\/UIApplicationDelegate_Protocol\/Reference\/Reference.html\" target=\"_blank\">UIApplicationDelegate Protocol Reference<\/a>, la documentazione ufficiale del protocollo UIApplicationDelegate.<\/p>\n<h4>L&#8217;autore<\/h4>\n<p>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 \u00e8 <a href=\"http:\/\/www.valeriodutto.com\" target=\"_blank\">http:\/\/www.valeriodutto.com<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In questo articolo analizzeremo il ciclo di vita delle applicazioni iOS, cio\u00e8 tutto ci\u00f2 che accade tra&#8230;<\/p>\n","protected":false},"author":544,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[9],"tags":[766,765,764,767,413],"class_list":["post-7032","post","type-post","status-publish","format-standard","hentry","category-guide-teoriche","tag-ciclo-di-vita-applicazioni-ios","tag-ciclo-di-vita-applicazioni-ipad","tag-ciclo-di-vita-applicazioni-iphone","tag-lezioni-programmazione-iphone","tag-programmare-iphone"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7032","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/544"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=7032"}],"version-history":[{"count":9,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7032\/revisions"}],"predecessor-version":[{"id":7045,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7032\/revisions\/7045"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=7032"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=7032"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=7032"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}