Automatic Reference Counting di Swift 3 spiegato in modo semplice per i beginners non laureati in Ingegneria informatica.

Questo articolo è stato scritto per chi non ha alcuna conoscenza (o quasi) del Memory Management. Molti corsi e libri su iOS tendono a saltare l’argomento perché in effetti può rivelarsi piuttosto complicato nel caso degli esordienti. Ad esempio, avete notato le keywords come weak e strong quando si crea IBOutlet? Probabilmente sì, perché in qualche modo funziona.

Prima di parlare di Swift, poniamo le basi nozionistiche rispetto al concetto di memoria e dei motivi per cui ci serve. Diciamo che questa parte si può saltare.

Il termine memory management si riferisce ad una visione d’insieme della gestione dei dati da parte del sistema operativo (iOS nel nostro caso) e in particolare al modo in cui salva ed estrae informazioni. Come già saprete, ci sono due metodi principali per salvare i data: 1. Disco ; 2. Random Access Memory (RAM).

Prerequisiti:

Una comprensione discreta di Object Oriented Programming, Optionals e Optional Chaining. Se vi siete persi, date un’occhiata al mio canale YouTube cliccando qui.

Lo scopo della RAM

Prendiamo il caso dei videogame. Il software avrà la necessità di salvare grandi quantità di immagini e grafica sul telefono, in modo che si possa proseguire nel gioco anche in seguito ad una pausa, ad esempio per andare in Impostazioni. Immaginate di arrivare ad un punto cruciale, mettere in pausa per alzare o abbassare il volume, tornare indietro e trovarvi di nuovo al punto di partenza. No, non deve essere piacevole.

Quando spegniamo il telefono, tutte quelle immagini saranno andate via dal momento che sono state salvate nella memoria RAM. Si tratta di uno storage temporaneo e rapido (circa 15,000 MB/s invece dei 1,000MB/s del normale hard drive). Le immagini di cui si parlava non vengono archiviate nel disco fisso: se così fosse stato, il telefono sarebbe colmo di file dopo un paio di giocate.

Spesso i docenti descrivono la RAM come una memoria a breve termine. Date uno sguardo al video qui sotto.

Lo scimpanzé ha una memoria a breve termine di gran lunga migliore rispetto agli essere umani, tuttavia nessuno dei due sarà capace di ricordare il pattern nel lungo termine.

Il mio iPhone ha 4GB di RAM e 128GB di hard drive. Quando si avvia un’app, quasi tutte le informazioni vengono memorizzate nella RAM, a meno che non si usi specificamente UserDefaults o CoreData per archiviarle su disco.

I limiti della RAM

Altro scenario. Sono le 2:00 di notte e invece di dormire siete su Instagram o Facebook. Come è possibile che lo smartphone sia in grado di reggere 60 frame a secondo ed una fluidità della transizione durante lo scroll? Come si può immaginare, è possibile perché quegli oggetti e i data vengono temporaneamente riposti nella RAM. In ogni caso, non si può archiviare in RAM a tempo indeterminato.

Quando diciamo “memory management”, in iOS ci riferiamo specificamente al processo di gestione dello spazio disponibile sulla RAM. Oggi il rischio di riempirla è raro, poiché di anno in anno si progredisce e si potenzia. In ogni caso, la regola fondamentale per gli sviluppatori iOS è quella di creare un’applicazione efficiente in modo da non intaccare le app che funzionano in background. In altre parole, dobbiamo rispettare il lavoro dei nostri colleghi facendo sì che ci sia abbastanza spazio per tutti su un unico dispositivo.

La RAM è come un frigorifero. Potete aggiungere cibo, bevande e perfino vestiti (se siete come me). Analogamente, in iOS è possibile aggiungere immagini, foto e oggetti pesanti come UIView. Come per il frigo, però, c’è un limite fisico che non può essere superato, così siamo costretti a tirare fuori qualche birra per metterci delle bottiglie d’acqua… o viceversa

Per fortuna in iOS 10 la pulizia della memoria viene eseguita in automatico da una libreria creata dagli ingegneri Apple, i quali hanno implementato Automatic Reference Counting al fine di distinguere gli oggetti ancora in uso e quelli non più necessari. Negli altri linguaggi di programmazione è necessario eseguire tale processo manualmente.

Ora siamo pronti per vedere come funziona Automatic Reference Counting.

Automatic Reference Counting

Prima di tutto, creiamo un oggetto. In questo caso è una classe chiamata “Passport” contenente la cittadinanza ed una optional property chiamata “Human” (che descriverò dopo). Per ora non dobbiamo conoscere la classe Human perché è un optional type.

A proposito, se non sapete cosa vuol dire deinit, è l’opposto di init. Con init si crea un oggetto e lo si inserisce nella memoria; il deinit avviene quando una specifica location dell’oggetto è stata liberata.

Creiamo un oggetto da solo, senza var o let.

Aspettate, perché viene cancellato appena dopo aver creato un oggetto/istanza? È dovuto ad ARC – lasciate che vi spieghi.

Per mantenere un oggetto in memoria deve esserci un riferimento a qualcosa, ed una relazione. So che suona strano, ma fidatevi.

Quando abbiamo creato l’oggetto Passport, questi non aveva alcuna relazione/reference. Ora, tuttavia, c’è una relazione tra myPassport e Passport e il reference count è una di queste.

***

Se il reference count è zero o non ha relazioni, l’oggetto viene eliminato dalla memoria.

***

Vi starete chiedendo cosa vuol dire strong: è una relazione di default. Una relazione aggiunge il reference count uno alla volta – spiegherò dopo, quando sarà necessario utilizzare weak.

Ora creo una classe chiamata “Human” con una optional property il cui type è “Passport”.

Dal momento che la variabile passport è un optional type, non dobbiamo impostarlo quando si inizializza un oggetto Human.

Se rendete nil sia “bob” che “myPassport”, allora

Appena si settano come nil per ogni oggetto, la relazione non esiste più e il reference count diventa 0 per ognuno. Ciò ne causa la rimozione.

Ad ogni modo, anche se impostate qualcosa a nil, non necessariamente andrà incontro alla rimozione – in particolare nel caso in cui abbia relazioni con altri oggetti, dunque non raggiungendo 0 nel reference count.

La classe Human aveva una optional property il cui type era Passport. Inoltre, Passport aveva una optional property il cui type era Human.

Ho realizzato uno scherma per chiarire la relazione.

 

Ora facciamo la stessa cosa settando a nil quegli oggetti.

Non accade niente, restano. Perché? Perché c’è ancora una relazione tra “bobby” e “newPassport”.

È necessario interrompere tutte le relazioni tra gli oggetti al fine di eliminare entrambi. Ad esempio, anche se Human con “Bob Lee” è stato settato a nel, non viene eliminato dal momento che intrattiene una relazione (reference count 1): Passport fa riferimento all’oggetto Human. Dunque, quando si prova a settare Passport su nil, questi non viene rimosso perché l’oggetto Human è ancora in vita ed ha una reference con Passport. Il reference count non raggiunge 0.

***

Non importa che abbiate settato gli oggetti a nil, dipende tutto dal numero di reference count. Si deve distruggere tutto. nil != rimozione — SangJoon Lee

***

Problema critico

Si chiamano reference cycle e memory leak. Anche se quegli oggetti non vengono più utilizzati e dunque si credeva di averli eliminati, restano sul telefono e occupano spazio come il grasso nel nostro organismo. Da evitare nel modo più assoluto. Immaginate se ci fosse un memory leak quando si naviga tra le foto di Instagram o i post di Facebook. I 4GB di RAM sarebbero riempiti da data objects fino a causare il blocco dell’app. Non è una bella esperienza.

Addio Strong, Benvenuto Weak

Congratulazioni, avete fatto parecchia strada. Ora imparerete il motivo per cui utilizziamo weak. L’unico scopo è quello di eliminare gli oggetti.

Ricordate, weak non aumenta il reference count. Aggiungiamolo di fronte alla proprietà Human all’interno della classe Passport.

Tutto il resto rimane invariato.

Ora, se si setta…

Ecco cosa accade. Dal momento che week non conta come relazione o non accresce il reference count, vi è virtualmente un solo reference count prima che si setti “bobby” a nil. Dunque, quando ciò avviene, il reference count / relazione diventa 0 e consente infine di distruggere tutto.

Adoro liberare la memoria ma… cavolo… ho impiegato una vita a scrivere questo articolo!

Source Code

***

Bob Lee è l’autore di questo articolo.

Articolo originale:Make Memory Great Again

 

NO COMMENTS

LEAVE A REPLY