CoreData e la proprietà “Allows External Storage”

In queste ultime settimane sto lavorando, più per passione che per altro, ad una nuova applicazione per iOS (che prima o poi vedrà la luce, spero). Questa app permette all’utente di inserire diverse informazioni, salvandole poi in CoreData. Tra le informazioni da salvare, però, ci sono anche delle immagini.

Proprio in merito alle immagini è sorta la grande domanda: come salvarle in CoreData? È possibile salvarle direttamente all’interno del database oppure è meglio memorizzarle all’esterno e inserire nel database solo il riferimento all’immagine?

Da buon laureato in sistemi informativi ho subito pensato: “Assolutamente non sono da salvare all’interno del database!” e mi sono messo a realizzare una mia implementazione. Tra una ricerca e l’altra su Google, però, ho trovato queste magiche parole: Allows External Storage.

screen1

Approfondendo la cosa ho scoperto di cosa si trattasse. Apple ha introdotto, con iOS 5, un’opzione che permette di realizzare in maniera del tutto automatica un sistema per gestire campi binari di grandi dimensioni.

Il funzionamento è molto semplice: se il file (foto, audio, documenti, etc) che dev’essere salvato in CoreData è di piccole dimensioni (circa 1 MB), questo viene salvato direttamente nel database, altrimenti viene salvato all’esterno (su disco) e nella base dati è inserito solo un riferimento a tale file.

Per verificare il funzionamento di questo meccanismo ho realizzato un piccolo progetto con CoreData, andando poi ad analizzare come effettivamente i dati erano stati salvati.

Il progetto

Ho creato un semplicissimo modello di CoreData, con un’entità ‘Photo’. Tale entità ha due attributi:

  • title, un semplice campo testo
  • photo, di tipo Binary Data, con l’opzione Allows External Storage attiva
screen2
screen3

Il codice al suo interno è molto semplice: creiamo tre istanze di Photo e salviamole all’interno di CoreData. Questi tre oggetti avranno associate delle immagini di diverse dimensioni:

  • photo-big.jpg, 3.7 MB
  • photo-small.jpg, 309 KB
  • photo-verysmall.jpg, 89 KB

Eccovi l’estratto di codice che effettua la creazione dei tre record:

// create and save three photos
UIImage *imageVerySmall = [UIImage imageNamed:@"photo-verysmall.jpg"];
Photo *photoVerySmall = [Photo createPhotoWithName:@"Photo Very Small" andPhoto:imageVerySmall inManagedObjectContext:[CoreDataBridge sharedManagedObjectContext]];

UIImage *imageSmall = [UIImage imageNamed:@"photo-small.jpg"];
Photo *photoSmall = [Photo createPhotoWithName:@"Photo Small" andPhoto:imageSmall inManagedObjectContext:[CoreDataBridge sharedManagedObjectContext]];

UIImage *imageBig = [UIImage imageNamed:@"photo-big.jpg"];
Photo *photoBig = [Photo createPhotoWithName:@"Photo Big" andPhoto:imageBig inManagedObjectContext:[CoreDataBridge sharedManagedObjectContext]];

if (!photoVerySmall || !photoSmall || !photoBig) {
    NSLog(@"Error during creation of photo objects");
} else {
    [CoreDataBridge saveSharedManagedObjectContect];
}

Dopo aver avviato l’applicazione (e di conseguenza creato i record all’interno del database), è giunto il momento di andare a verificare come si comporta CoreData dietro le quinte.

Analisi

Spostiamoci nella cartella del simulatore che contiene l’app appena creata e i suoi dati (si trova nella directory

/Users/{USERNAME}}/Library/Application Support/iPhone Simulator/{IOS_VERSION}/Applications/{IDAPP}
screen4

All’interno della cartella Documents troviamo

  • coredataexternalstorage.sqlite, è il database SQLite alla base di CoreData
  • .coredataexternalstorage_SUPPORT, cartella in cui vengono salvati i file di grandi dimensioni

Navigando nella cartella coredataexternalstorage_SUPPORT troviamo due delle fotografie che abbiamo salvato: sono effettivamente le due di maggiori dimensioni.

screen5

Apriamo il file .sqlite per verificare che CoreData si salvi effettivamente solo il riferimento a tali immagini. Nei due screen seguenti questo viene effettivamente confermato: per la foto “Photo Small” è stato salvato il riferimento all’immagine salvata su disco, mentre nel caso di “Photo Very Small” il campo “photo” contiene la fotografia vera e propria.

screen6
screen7

CoreData, quindi, si è occupato per noi di decidere quali file salvare all’interno del database e quali, invece, all’esterno, perchè troppo grandi.

È la soluzione ottimale?

“Allows External Storage” è la soluzione ottimale? Non lo so. La questione è molto dibattuta e controversa. In rete si trovano molti sviluppatori che preferiscono scriversi da soli una soluzione a questo problema, ignorando quindi la soluzione proposta da Apple.

Personalmente non amo reinventare la ruota, quindi la mia idea è di utilizzare questa “magica” opzione, che sicuramente evita parecchio lavoro. Sarebbe interessante capire se, in termini di prestazioni, questa soluzione sia ottimale oppure possa provocare dei problemi.

Ingegnere informatico e sviluppatore freelance, mi occupo da anni di sviluppo per iOS (ma non solo). Dal 2008 scrivo su questo piccolo blog (con qualche lunga pausa), in cui parlo di programmazione e di qualsiasi altra cosa che mi diverta.

Leave a reply:

Your email address will not be published.

Site Footer