{"id":1069,"date":"2009-12-03T09:28:37","date_gmt":"2009-12-03T08:28:37","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=1069"},"modified":"2010-11-05T16:39:42","modified_gmt":"2010-11-05T15:39:42","slug":"l008-objective-c-parte-iii","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/l008-objective-c-parte-iii\/","title":{"rendered":"L#008 \u2013 Objective-C (Parte III) Gestiamo la memoria"},"content":{"rendered":"<p>In questo articolo analizzeremo un aspetto della programmazione per iphone che spesso \u00e8 responsabile di lunghe ore di debug e di frustrazione. Stiamo parlando, ovviamente, della gestione della memoria.<br \/>\n\u00c8 bene precisare che tutto quello che diremo qui si applica solo agli oggetti nativi dell&#8217; Objective-C mentre per le variabili dichiarate con la sintassi C (int, char, float) restano valide le regole di questo linguaggio.<!--more--><\/p>\n<p>Una corretta e attenta gestione della memoria sui dispositivi mobili e, soprattutto, su<strong> ipod\/iphone<\/strong> \u00e8 di cruciale importanza, viste le ridotte capacit\u00e0 di elaborazione di questi device.<br \/>\nProprio per le ridotte capacit\u00e0 di elaborazione \u00e8 stato necessario privare i nostri iphone di una vera e propria Garbage Collection, utilizzando in sua vece un pi\u00f9 complesso <strong>Autorelease Pool<\/strong>.<br \/>\nMa quali sono le differenze? La GC monitora costantemente i nostri oggetti, i quali vengono eliminati solo su nostra richiesta o quando non esistono pi\u00f9 riferimenti per accedere a quell&#8217;oggetto. Questo\u00a0 implica che se esiste un riferimento ad un oggetto, questo \u00e8 sicuramente valido.<br \/>\nL&#8217;autorelease pool invece \u00e8 l&#8217;esatto contrario, elimina tutti gli oggetti, tranne quelli per i quali abbiamo fatta esplicita richiesta che vengano mantenuti. Il motivo di tale approccio \u00e8 facilmente intuibile, ed \u00e8 da ricercare nel fatto che nei device attuali la memoria \u00e8 un bene prezioso e ci non possiamo permettere che i nostri programmi la sprechino.<\/p>\n<p>L&#8217;autorelase viene istanziato nel main delle nostre applicazioni, con questa istruzione:<\/p>\n<pre lang=\"objc\" escaped=\"true\">NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];<\/pre>\n<p>e lo possiamo considerare quindi alla stessa stregua del tristo mietitore pronto ad eliminare tutti gli oggetti ritenuti inutili, compito che svolge analizzando una particolare propriet\u00e0 di ogni oggetto chiamata <em>retainCount. <\/em>In particolare vengono eliminati tutti quegli oggetti che hanno un valore di <em>retainCount<\/em> pari a zero.<br \/>\nPer far funzionare il nostro programma secondo le nostre aspettative dovremo quindi fare in modo che gli oggetti necessari\u00a0 abbiamo <em>retainCount<\/em> maggiore o uguale a 1.<\/p>\n<p>Se per qualche ragione siamo interessati a sapere quando l&#8217;autorelease elimina i nostri oggetti, possiamo sfruttare il fatto che viene invocato in maniera trasparente il metodo <em>dealloc <\/em>sull&#8217;oggetto da eliminare, quindi eseguendo un opportuno override di questo metodo possiamo ottenere tutte le informazioni di cui abbiamo bisogno.<\/p>\n<p>Quali sono quindi i momenti in cui <em>retainCount <\/em>varia?<\/p>\n<ul>\n<li>Quando una variabile viene inizializzata il suo <em>retainCount<\/em> viene incrementato di 1.<\/li>\n<li>I metodi <em>alloc, copy, allocWithZone <\/em>incrementano <em>retainCount <\/em>di 1.<\/li>\n<li>I metodi <em>release, autorelease <\/em>decrementano <em>retainCount <\/em>di 1. (autorelease lo fa in un momento non deterministico)<\/li>\n<li>Se non diversamente specificato il metodo <em>autorelease <\/em>viene invocato di default.<\/li>\n<\/ul>\n<p>Vediamo qualche esempio:<\/p>\n<pre lang=\"objc\" escaped=\"true\">TheClass *newObject = [[TheClass alloc] init];<\/pre>\n<p>In questo caso il <em>retainCount <\/em>di newObject sar\u00e0 1\u00a0 per via del metodo <em>alloc. <\/em>(in realt\u00e0 riceve anche un +1 per l&#8217;inizializzazione e un -1 per l&#8217;autorelease implicito)<br \/>\nL&#8217;area di memoria assegnata a questo oggetto quindi non potr\u00e0 essere liberata, neanche quando usciremo dallo scope della variabile newObject. In questo caso avremo perso ogni riferimento a questo oggetto e avremo creato quello che viene chiamato <strong>leak<\/strong>.<\/p>\n<pre lang=\"objc\" escaped=\"true\">NSString *myString = @\"Hello World\";<\/pre>\n<p>In questo caso il <em>retainCount <\/em>di <em>myString <\/em>sar\u00e0 pari a zero, perch\u00e8 +1 lo ricever\u00e0 per via della inizializzazione e -1 per via dell&#8217; <em>autorelease <\/em>implicito. Questo significa che la zona di memoria assegnata a <em>myString <\/em>verr\u00e0 liberata dall&#8217;<em>autoreleasePool <\/em>nonappena questi lo riterr\u00e0 opportuno, non prima del termine dell&#8217;esecuzione del metodo corrente per\u00f2!<\/p>\n<pre lang=\"objc\" escaped=\"true\">NSString *myString = [NSString stringWithFormat:@\"HELLO WORLD\"] autorelease];<\/pre>\n<p>Stesso caso del precedente ma con la chiamata esplicita di <em>autorelease.<\/em><\/p>\n<p>Facciamo un piccolo esempio per comprendere quando sia indispensabile la far propri questi meccanismi. Dichiariamo in una nostra classe una variabile (variabile di istanza)<\/p>\n<pre lang=\"objc\" escaped=\"true\">NSString *myString<\/pre>\n<p>La inizializziamo in un metodo, e vi accediamo da un secondo.<\/p>\n<pre lang=\"objc\" escaped=\"true\">- (void)viewDidLoad {\r\n    myString = [[NSString stringWithFormat:@\"ciao\"] autorelease];\r\n    [super viewDidLoad];\r\n}\r\n\/\/..altro codice...\r\n- (IBAction)otherMethod:(id)sender{\r\n   NSLog(myString);\r\n}<\/pre>\n<p>Questo codice per quanto sembri corretto invece andr\u00e0 in errore, perch\u00e8 avendo chiamato il metodo <em>autorelease <\/em>sull&#8217;oggetto myString ne abbiamo portato il <em>retainCount <\/em>a zero, quindi viene eliminata dall&#8217;<em>autorelease pool.<\/em><\/p>\n<p>Un caso ancora pi\u00f9 significativo avviene quando gli oggetti diventano parametri dei nostri metodi, vediamo questo codice:<\/p>\n<pre lang=\"objc\" escaped=\"true\">\/\/CLASSE 1\r\n- (void)metodo1{\r\n\tNSString *saluto = [NSString stringWithFormat:@\"Ciao mondo\"];\r\n\t[classe2 metodo2:saluto]\r\n}\r\n\/\/CLASSE2\r\nNSString *newString;\r\n- (void)metodo2:(NSString *)str{\r\n   newString = str;\r\n}\r\n- (void)metodo3{\r\n   NSLog(newString);\r\n}<\/pre>\n<p>L&#8217;invocazione del metodo3 causer\u00e0 un crash della nostra applicazione perch\u00e8 l&#8217;oggetto stringa <em>saluto<\/em> definita nel metodo1, \u00e8 di tipo <em>autorelease<\/em> e quindi verr\u00e0 rimosso dall&#8217;<em>autorelease pool. <\/em>All&#8217;interno del metodo2 l&#8217;operazione newString=str non fa altro che assegnare al puntatore <em>newString<\/em> lo stesso indirizzo di\u00a0 <em>str<\/em> che era lo stesso di <em>saluto<\/em> (ricordiamoci che in fondo parliamo sempre di puntatori C ) quindi quando l&#8217;oggetto <em>saluto <\/em>verr\u00e0 eliminato i riferimenti all&#8217;interno di <em>newString <\/em>non saranno pi\u00f9 validi ed ogni tentativo di accesso produrr\u00e0 il famoso errore EXC_BAD_ACCESS.<\/p>\n<p>Alla prossima.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/supporto-applicazioni\/parole-vietate-di-ignazio-calo\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2264\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/02\/bannerIgnazioc.png\" alt=\"\" width=\"480\" height=\"100\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/02\/bannerIgnazioc.png 480w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/02\/bannerIgnazioc-300x62.png 300w\" sizes=\"auto, (max-width: 480px) 100vw, 480px\" \/><\/a><br \/>\n<\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In questo articolo analizzeremo un aspetto della programmazione per iphone che spesso \u00e8 responsabile di lunghe ore&#8230;<\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[9],"tags":[6,55,5,18,4,17],"class_list":["post-1069","post","type-post","status-publish","format-standard","hentry","category-guide-teoriche","tag-iphone","tag-memoria","tag-objective-c","tag-oop","tag-programmazione","tag-teoria"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/1069","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\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=1069"}],"version-history":[{"count":21,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/1069\/revisions"}],"predecessor-version":[{"id":5014,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/1069\/revisions\/5014"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=1069"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=1069"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=1069"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}