Compatibile con Xcode 8

Salvare immagini in Memoria con Core Data

ENTRA NEL NOSTRO GRUPPO FACEBOOK

Questo è un estratto di un intero modulo del corso di sviluppo applicazioni iOS con Swift. Buona lettura ;)

Nella prima lezione introduttiva al Core Data, nelle impostazioni delle Entity, ti ho fatto notare la non presenza di un tipo di dato che descrivesse un’immagine. Questo non deve trarti in inganno perché ciò non significa che il Core Data non permetta il salvataggio delle immagini in memoria.

Generalmente il salvataggio d’immagini in un Database è un’operazione, spesso e volentieri, sconsigliata per via delle dimensioni notevoli che possono assumere alcune immagini. In genere non si salvano mai immagini superiori ad 1 MB perché i database comincerebbero a perdere la famosa velocità osannata nel tutorial introduttivo.

Come si fa? L’approccio più utilizzato è quello di memorizzare all’interno del database il path o percorso del documento/immagine. Grazie a questo path si riesce a raggiungere il vero e proprio file che, in molti casi, viene conservato in una cartella specifica.

Ora, se ricordi bene, ti ho detto che il Core Data non è un Database bensì una tecnologia che fa da intermediario. Quindi la vera domanda è: com’è che riusciremo a salvare le immagini in memoria con il Core Data?

Tra i tipi di dati possibili, per gli attributi di una Entity del Core Data, è presente anche il Binary Data (dati in formato binario). Per non dilungarmi troppo sulla natura dei file binari, ti dico subito che qualsiasi oggetto può essere rappresentato in notazione binaria: cioè come file composto da 0 e 1, ovvero in bit (bit = l’unità fondamentale di qualsiasi computer).

Binary Data Core Data

Utilizzando il tipo di dato Binary Data sarai in grado di salvare le immagini con il Core Data. Ovviamente, non è possibile inserire l’UIImage nella proprietà che ha il tipo binary data. Infatti, com’è plausibile, è necessaria un’opportuna conversione da UIImage in NSData (l’oggetto che descrive i Binary Data).

Piccola digressione. L’NSData non è la classe per la rappresentazione delle date del calendario. C’eri cascato pure tu? In inglese “data” significata “dati o informazione”. Mentre la classe che descrive le date del calendario è la NSDate. Piccole pillole che possono salvare il tuo progetto dall’autocombustione.

External Storage

In effetti salvare un’immagine su Binary Data non è comunque una scelta ottimale. Le immagini, come ti dicevo, hanno un peso che supera i megabyte che le renderebbero pesanti anche se fossero convertite in formato binary data.

Il Core Data oltre a fornirti il salvataggio in Binary Data, ti permetterà di salvare l’informazione convertita in NSData in una posizione differente rispetto al database nel quale verrà conservato l’NSManagedObject. L’NSManagedObject risiederà normalmente nel Database, mentre, l’immagine convertita in binary data verrà posizionata nel File System del tuo iPhone/iPad (per semplicità puoi pensare le immagini come salvate in una cartella del tuo dispositivo). Così facendo il recupero degli oggetto NSManagedObject risulterà più veloce ed immediato.

Per abilitare il salvataggio di una proprietà Binary Data direttamente sul File System devi selezionare l’opzione “Allow External Storage”:

allow external storage core data

L’Allow External Storage non avrà nessuna ripercussione sulla tua proprietà Binary Data. Dunque, anche se abilitato, l’immagine, verrà sempre restituita in formato Binary Data ovvero come oggetto NSData. 

Codice

Dato che concettualmente le nozioni sono uguali alle lezioni precedenti, l’unico step da analizzare è la conversione di un’UIImage in NSdata e viceversa. Ti ricordo che, se stai lavorando con le UIImageView, l’immagine è contenuta all’interno della proprietà image.

Nel mio progetto ho una Entity con due proprietà. Una proprietà “nome” che descriverà l’immagine ed una proprietà “binary_img” che conterrà l’immagine.

Una volta che avrai creato la classe di riferimento, entra dentro l’extension ed aggiungi la seguente funzione (assicurati di aver importato l’UIKit):

Il metodo UIImageJPEGRrepresentation trasforma una UIImage da qualsiasi formato utilizzato in JPEG in formato Binary Data (come NSData). Infatti il metodo restituisce un NSData nel caso di conversione avvenuta con successo o nil altrimenti. Il secondo parametro definisce la compression quality, cioè la qualità che dovrà mantenere l’immagine una volta convertita. Un valore uguale ad 1 mantiene la qualità dell’immagine originale. Più ci si avvicina allo zero e più calerà la qualità e, automaticamente, anche il peso.

Ti basterà utilizzare questo metodo per salvare l’immagine dentro la tua proprietà NSData.

Al contrario, per convertire l’NSData in UIImage, potrai utilizzare il costruttore della classe UIImage che accetta in ingresso un NSData:

Thumbnail e aumento delle prestazioni

Un sistema intelligente per l’ottimizzazione degli spazi e della velocità di caricamento degli oggetti è quella di utilizzare una versione ridotta o Thumbnail dell’immagine originale.

Pensa, per esempio, ad una tabella che mostra 100 o più elementi e dove, ad ogni riga, deve mostrare un’anteprima dell’immagine. Un conto sarà caricare 100 immagini con massima risoluzione ed un altro conto sarà fare la stessa operazione con immagini ridotte.

Poco fa ti ho fatto vedere che il metodo UIImageJPEGRrepresentation ti da la possibilità di creare un NSData di un’immagine con risoluzione inferiore all’originale (modificando il secondo parametro). Potremmo, quindi, sfruttare tale proprietà per creare delle versioni ridotte delle immagini originali.

Ma, dove aggiungere la versione ridotta dell’immagine?

Aggiungere una nuova proprietà NSData all’Entity che descrive l’immagine originale (o comunque dove è presente l’oggetto principale) non è la scelta ottimale. Avresti due proprietà NSData con lo stesso contenuto che appesantirebbero inutilmente l’oggetto.

La strategia da adottare è quello di una seconda Entity, chiamata Thumbnail, collegata con una relazione One-To-One all’Entity Principale. All’interno di questa salverai l’immagine ridotta con lo stesso sistema visto poco fa:

Thumbnail e Core Data

Ovviamente il ragionamento può essere fatto anche al contrario. Ovvero la thumbnail può essere inserita nell’Entity principale e l’immagine originale in un’altra. Cosa che renderebbe più leggera l’entity nel caso in cui lavorassi principalmente con questa.

Tutto dipende dall’utilizzo che fai delle Entity. Se utilizzi un’entity più spesso rispetto ad un’altra, inserisci la thumbnail in questa e l’immagine originale in un’Entity associata.

Considerazioni

Non ho voluto creare un esempio perché effettivamente non c’è molto da provare. Sarebbe un cut and paste dei codici delle precedenti lezioni. Quindi ho preferito descrivere in maniera più veloce questa proprietà per darti subito modo di mettere in pratica queste conoscenze.

Per qualsiasi dubbio sull’utilizzo di quest’opzione, lascia pure un commento.

Buona Programmazione!

Start typing and press Enter to search