Ed eccoci al terzo appuntamento, come avrete visto l’applicazione inizia prendere forma, la prima delle tre funzionalità che abbiamo evidentizato è pronta e funzionante.
Una precisazione…lo scopo di questo tutorial non è realizzare un’applicazione perfetta e priva di difetti, il codice che abbiamo scritto è completamente privo di qualsiasi gestione degli’errori e questo non è ammissibile in una applicazione seria.
Realizziamo allora la seconda funzionalità del nostro programma, il parser xml.
Vogliamo in pratica realizzare un parser che sia in grado di esaminare il file xml già scaricato e fornire un elenco di url per visualizzare le foto.
Creiamo quindi una nuova classe, figlia di NSObject e la chiamiamo URLbuilder (se non sapete come fare leggete la puntata precedente).
Direi che ci servono almeno due variabili, una di tipo NSData che conterrà il file XML per intero e un NSMutableArray che conterrà il risultato del nostro parsing, ovvero gli url delle foto.
Dichiariamo quindi queste due variabili nel file URLbuilder.h in questo modo:
@interface URLbuilder : NSObject {
NSMutableArray *URLarray;
NSData *XMLdata;
}
@end
e creiamo i metodi getter e setter come abbiamo visto nella lezione precedente. (prometto che farò un tutorial sull’uso di property..)
Per i più svogliati ecco il codice:
- (void) setURLarray:(NSMutableArray *)anArray
{
URLarray = anArray;
}
- (NSMutableArray *)getURLarray
{
return URLarray;
}
- (void) setXMLdata:(NSData *)data
{
XMLdata = data;
}
- (NSData *) getXMLdata
{
return XMLdata;
}
Direi di creare anche un metodo initWithXMLData che ci permetterà, quando utilizzeremo questa classe di inizializzarla e impostare il valore di XMLData in una sola istruzione.
ecco il codice:
- (id)initWithXMLdata:(NSData *)data
{
if (self = [super init])
{
[self setXMLdata:data];
}
return self;
}
Restano da dichiarare i metodi veri e propri per il parsing del file xml, vi consiglio di leggere (se non l’avete ancora fatto) i tutorial a tal proposito che trovate su questo stesso sito,io darò per scontato che l’abbiate fatto, quindi vediamo e commentiamo subito il codice:
- (NSMutableArray *) startParsing
{
NSXMLParser *feedParser = [[NSXMLParser alloc] initWithData:[self getXMLdata]];
[feedParser setDelegate:self];
[feedParser parse];
[feedParser release];
}
Questo è il metodo che dobbiamo invocare per avviare il parsing, istanziamo quindi un oggetto di tipo NSXMLParser inizializzandolo con il contentuto del file XML, impostiamo a SELF il delegate e lo avviamo. Infine rilasciamo l’oggetto per evitare memory leak.
Forse è il caso di specificare che cosa significhi impostare il delegate, perché è un concetto fondamentale della programmazione MVC (model view controller) e quindi della programmazione per iphone.
Abbiamo già parlato di delegate nell’articolo relativo all’UIPickerView, e anche se parliamo di oggetti diversi la logica che ci sta dietro è identica.
In particolare l’oggetto NSXMLParser è un parser asincrono, il che significa che una volta lanciata la procedura di parsing il codice non sta “fermo” ad aspettare che la procedura termini, sarà il parser stesso ad inviare al proprio delegate specifici messaggi per informarlo di come procede il suo lavoro. Non si può dire lo stesso per esempio del metodo
[NSData dataWithContentsOfURL:[NSURL URLWithString:fullAddress]];
che abbiamo utilizzato la scorsa lezione, questo metodo “blocca” l’esecuzione del codice fin quando non ha finito.
Questa sarà una informazione da tenere bene a mente nella creazione dell’interfaccia grafica, e lo vedremo bene nella prossima lezione.
In pratica impostare il delegate per l’NSXMLParser significa “delegare” una classe a rispondere ai messaggi inviati da questo oggetto. Questo si traduce nell’implementare alcuni metodi che trovate specificati nella NSXMLParserDelegate Protocol Reference, alcuni sono facoltativi, mentre altri sono obbligatori.
Questo potrebbe essere chiamato “binding dinamico”, ovvero la possibilità di associare ad un evento (in questo caso il messaggio ricevuto dalla classe NSXMLParser) ad una diversa risposta a seconda di chi quale sia in quel momento il delegate.
Vediamo quindi quali sono i metodi che abbiamo deciso di implementare nel nostro delegate (il che significa anche “a quali messaggi del parser intendiamo rispondere”)
//INIZIA IL PROCESSO DI PARSING
- (void) parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(@"PARSING STARTED\n");
[self setURLarray:[NSMutableArray arrayWithCapacity:100]];
}
Questo metodo viene invocato quando viene avviato il processo di parsing.
Inizializziamo in questo momento l’array che conterrà gli URL, poiché per impostazione predefinita Flickr manda un file XML contenente le informazioni per recuperare 100 fotografie settiamo la dimensione del nostro array proprio a 100.
- (void) parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(@"PARSING TERMINATO\n");
if ([[self getURLarray] count] == 0) {
NSLog(@"ERRORE");
}
}
Questo metodo viene invocato quando il parser termina il suo lavoro.
Utilizzo un paio di NSLog per verificare se il parsing è andato a buon fine.
Se l’array con i link contiene zero elementi questo significa che c’è stato un errore.
//INIZIA IL RICONOSCIMENTO DI UN ELEMENTO
- (void) parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:@"photo"]) {
[[self getURLarray] addObject:[NSMutableString stringWithFormat:@"http://farm%@.static.flickr.com/%@/%@_%@_m.jpg",
[attributeDict objectForKey:@"farm"],
[attributeDict objectForKey:@"server"],
[attributeDict objectForKey:@"id"],
[attributeDict objectForKey:@"secret"]]];
}
}
Questo forse è il metodo più importante, viene invocato quando il parser riconosce l’inizio di un nuovo tag.
Come possiamo vedere da questa immagine, il file XML fornito da Flickr è costituito da un tag “RSP” che contiene l’esito della risposta, poi un tag “PHOTOS” che fornisce alcune indicazioni riguardo al numero di foto e di pagine (ricordo che c’è la possibilità ri richiedere una specifica pagina o un numero specifico di foto anzichè i valori di defaut) e poi un certo numero di tag “PHOTO” con tutti i dati delle fotografie.
Noi siamo interessati solo a quest’ultimo tag, ecco perché nel codice ho scritto
if ([elementName isEqualToString:@"photo"])
A questo punto possiamo costruire finalmente l’URL della foto, per fare questo costruiamo una stringa secondo le istruzioni fornite da flickr a questa pagina: http://www.flickr.com/services/api/misc.urls.html
Nel codice che ho scritto ho aggiunto “_m” perché voglio ottenere l’url della versione a grandezza media della foto.
Creato quindi l’url non resta che aggiungerlo all’array URLarray per scopi futuri.
Come al solito chiediamo un pò di gratificazione dopo tutto questo lavoro, vogliamo quantomeno vedere che cosa abbiamo ottenuto..
modifichiamo quindi il file devFlickrViewController.m e modifichiamo il metodo ViewDidLoad in questo modo:
- (void)viewDidLoad {
[super viewDidLoad];
interestingness *inter = [[interestingness alloc] initWithApiKey:@"MY_API_KEY_IS_PRIVATE"];
NSData *tmp;
tmp = [inter downloadXML];
URLbuilder *urlBuilder = [[URLbuilder alloc] initWithXMLdata:tmp];
[urlBuilder startParsing];
NSLog(@"%@",[[urlBuilder getURLarray] description]);
}
Eseguendo l’applicazione ed esaminando la console vedremo finalmente gli url delle foto.
Utilizzeremo questo array nella prossima lezione per visualizzare le foto nella nostra applicazione, questo ci permetterà di affrontare il problema dei thread, quindi NON MANCATE!












No Responses to “T#048 – Accedere a Flickr dalle nostre applicazioni iPhone (parte 3)”