Salve a tutti, nel tutorial di oggi vedremo come scaricare immagini da internet per arricchire la nostra applicazione. Il mio caso era piuttosto particolare, avevo la necessità di scaricare delle nuove ricette, e caricarle programmaticamente all’interno del DB SQLite. La soluzione é ricaduta nel far puntare l’applicativo all’indirizzo di un file XML su web. Il file xml (che viene parsato in SAX mode), legge i dettagli e crea un record nel DB. La ricetta però è formata sia da campi testuali, che da immagini, occorreva quindi avere un modo per scaricare in background anche tali assets binari.
Vediamo un pò di codice:
string contiene il nome dell’immagine es: “carbonara.png”
imageURLString contiene l’url dell’immagine (aggiungendo il prefisso del sito)
NSString *imageURLStringSito = @"http://www.sviluppoiphoneitalia.com/ricette_romane/";
NSString *imageURLString = [NSString stringWithFormat: @"%@%@", imageURLStringSito, string];
Creiamo ora un NSURL con il path completo su internet:
NSURL *ImageURL = [NSURL URLWithString: ImageURLString];
Come forse già saprete, non ci è possibile scrivere nel path del bundle, o all’interno della nostra applicazione.
Quindi il suggerimento di Apple è quello di scrivere all’interno della directory Documents della nostra applicazione. La directory Documents viene creata per default per ogni applicazione, quindi non dovremo preoccuparci di verificare che esista o meno, tra l’altro è la prima directory che torna il metodo di retrieve di tutte le directory dell’applicativo.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filename = string; //nome del file su disco, possiamo anche chiamarlo in altro modo
Nome del file completo su filesystem:
NSString *fullPathToFile = [documentsDirectory stringByAppendingPathComponent:filename];
printf("Path completo file:'%s' ", [fullPathToFile UTF8String]);
Questo controllo ci serve per non sovrascrivere un’immagine già scaricata
if(![[NSFileManager defaultManager] fileExistsAtPath: fullPathToFile])
{
NSData *data = [[NSData alloc] initWithContentsOfURL: ImageURL];
UIImage *image = [[UIImage alloc] initWithData: data];
Il codice che segue verifica l’estensione, nel caso sia un file .png scrive l’immagine così com’ è, nel caso si tratti, invece, di un jpeg o jpg, allora deve specificare il rapporto di qualità (nel nostro caso 100%).
if([ImageURLString rangeOfString: @".png" options: NSCaseInsensitiveSearch].location != NSNotFound)
{
[UIImagePNGRepresentation(image) writeToFile: fullPathToFile atomically: YES];
}
else if(
[ImageURLString rangeOfString: @".jpg" options: NSCaseInsensitiveSearch].location != NSNotFound ||
[ImageURLString rangeOfString: @".jpeg" options: NSCaseInsensitiveSearch].location != NSNotFound
)
{
[UIImageJPEGRepresentation(image, 100) writeToFile: fullPathToFile atomically: YES];
}
} //chiudo --if(![[NSFileManager defaultManager] fileExistsAtPath:....
Spero vi torni utile questo tutorial, questa di seguito è l’applicazione citata da cui è tratto il nostro tutorial: Ricette Romane
Alla prossima.











10 Responses to “T#033 – Salvare immagini da internet nella nostra applicazione”
14 Aprile 2010
NormAppsCiao, bel tutorial, molto utile! Ho visto la tua app, e mi sembra molto interessante. Sto tentando anche io di fare un ricettario, ma in modo diverso: sull’iPad ho creato una Split View, mettendo diverse voci alla Root, una per ogni ricetta, usando immagini e titoli diversi, ma non so come mettere un testo diverso per ogni ricetta (ovvero la ricetta in se, con ingredienti e tutto.) Mica potresti darmi qualche consiglio su come fare? Grazie! Mi piacerebbe implementare anche questa funzione del tutorial, sarebbe utile per poterlo aggiornare 😀
14 Aprile 2010
sarnieriIl modo migliore per studiare un’app é averla sul proprio dispositivo! 😀
Io ho organizzato il ricettario con un DB sqlite, ho una tabella per la ricetta, una per le categorie e una per gli ingredienti con una chiave esterna che collega l’elemento ingrediente alla sua ricetta.
I dati della ricetta sono i classici, titolo, tempo di cottura, tempo di preparazione, vino consigliato, idCategoria, flag preferito, testo della preparazione etc…
Ho creato poi una classe “Ricetta” con tutti questi attributi
(compreso un campo nsmutablearray per gli ingredienti) e me lo rimbalzo da schermata a schermata man mano che entro nei vari dettagli.
La cosa é un pó piú complicata di come sembra per la schermata di dettaglio della ricetta, ci sono dei pulsanti variabili, e il tutto é inserito non in una scheda di dettaglio classica con oggetti presi e messi lí tramite IB e collegati, ma creati tutti dinamicamente da codice perché dentro una tabella!
Inoltre alcune celle hanno richiesto piú lavorazione di altre es. la preparazione ha un’altezza variabile a seconda del testo inserito, quindi bisogna calcolare l’occupazione tramite la grandezza del font e il numero di righe etc…
Ho inoltre implementato la funzione di poter creare da soli una ricetta dal dispositivo, inserendo tutti i dati compresa un’immagine scattata onfly etc…
se mi fai qualche domanda piú specifica cercheró di darti delle risposte piú utili.
Gino
14 Aprile 2010
Fastanche a me piacerebbe sapere come visualizzare testi diversi per ogni elemento del root
14 Aprile 2010
sarnieriNon riesco a capire la domanda, nel senso, il dubbio é su come creare una cella diversa per ogni elemento della tabella dettaglio ricette o cosa?
g.
14 Aprile 2010
Fastpiù che altro si collega al tutorial dell’altro giorno sulle split view, che invece di vedere ogni immagine diversa per elemento, bisogna vedere del testo (una descrizione) diversa per elemento
14 Aprile 2010
NormAppsAllora, tenterò di essere più preciso. Vedo che tu te ne intendi già abbastanza, mentre io sono proprio alle prime armi come programmazione. Nella sezione iPad del sito ho trovato il tutorial per la Split View e l’ho seguito, e sono riuscito a creare una lista di categorie (cioè di ricette singole) da poter scegliere. Nel tutorial però mostra solo come mettere un testo uguale ad ogni categoria, che è “Testo %@”, con alla fine il nome della ricetta in questione. Così quindi è inutilizzabile, perché dovrei capire come poter scrivere un testo diverso per ogni ricetta/categoria. Non voglio iniziare a fare cose “complicate” (che magari per te saranno banali) per non complicarmi il tutto, per ora voglio solo aggiungere un testo diverso ad ogni ricetta. Grazie per il supporto!
14 Aprile 2010
sarnieriAh chiaro, ho letto anche io l’ottimo articolo, ma purtroppo sviluppando su un sdk 3.1.2 non posso fare esperimenti con il simulatore iPad, temo che dovrete quindi chiedere in coda all’altro tutorial!
g.
14 Aprile 2010
NormAppsPenso che per questa cosa il codice sia analogo su entrambe le parti, l’unica differenza è la split view ma non è quello il problema. Se non riesci fa niente, grazie comunque 😉
14 Aprile 2010
sarnieriTi dico come lo farei io, non so se per le split view ci sono dei metodi scorciatoia o delle best practice.
In pratica ogni volta che passo da una tabella ad un’altra (tipo da quella delle categorie a quella delle ricette nella categoria, o dalla lista delle ricette al dettaglio etc…) prima di richiamare il metodo di visualizzazione della view gli setto un oggetto che esporto tramite il suo “.h”.
L’oggetto di cui parlo é appunto “ricetta”.
Quindi ipotizzando che sto vedendo una lista di ricette, mi posiziono nel metodo che intercetta il click su una riga e scrivo:
//metodo per il tap su una riga
– (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//prendo l’elemento selezionato
NSMutableDictionary *ricettaScelta = [tableDataSource objectAtIndex:indexPath.row];
DettaglioRicetta *dvController = [[DettaglioRicetta alloc] initWithNibName:@”DettaglioRicetta” bundle:[NSBundle mainBundle]];
dvController.ricetta = ricettaScelta ;
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
}
Ma ripeto, forse nelle split view c’é un metodo piú elegante!
8 Luglio 2011
LucaRagazzi io non capisco come scrivere e leggere su file: la mia esigenza è salvare un URL su file (immagino nella cartella documents) per poi rileggerlo all’apertura dell’app.