{"id":3585,"date":"2010-06-02T09:30:26","date_gmt":"2010-06-02T07:30:26","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=3585"},"modified":"2010-11-05T16:44:02","modified_gmt":"2010-11-05T15:44:02","slug":"t048-accedere-a-flickr-dalle-nostre-applicazioni-iphone-parte-3","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/t048-accedere-a-flickr-dalle-nostre-applicazioni-iphone-parte-3\/","title":{"rendered":"T#048 \u2013 Accedere a Flickr dalle nostre applicazioni iPhone (parte 3)"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"alignleft\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/05\/logo_flickr.jpg\" alt=\"\" width=\"223\" height=\"111\" \/> Ed eccoci al terzo appuntamento, come avrete visto l&#8217;applicazione inizia prendere forma, la prima delle tre funzionalit\u00e0 che abbiamo evidentizato \u00e8 pronta e funzionante.<br \/>\nUna precisazione&#8230;lo scopo di questo tutorial non \u00e8 realizzare un&#8217;applicazione perfetta e priva di difetti, il codice che abbiamo scritto \u00e8 completamente privo di qualsiasi gestione degli&#8217;errori e questo non \u00e8 ammissibile in una applicazione seria.<br \/>\nRealizziamo allora la seconda funzionalit\u00e0 del nostro programma, il parser xml.<br \/>\nVogliamo in pratica realizzare un parser che sia in grado di esaminare il file xml gi\u00e0 scaricato e fornire un elenco di url per visualizzare le foto.<!--more--><br \/>\nCreiamo quindi una nuova classe, figlia di NSObject e la chiamiamo URLbuilder (se non sapete come fare leggete la puntata precedente).<br \/>\nDirei che ci servono almeno due variabili, una di tipo NSData che conterr\u00e0 il file XML per intero e un NSMutableArray che conterr\u00e0 il risultato del nostro parsing, ovvero gli url delle foto.<br \/>\nDichiariamo quindi queste due variabili nel file URLbuilder.h in questo modo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">@interface URLbuilder : NSObject {\r\n\tNSMutableArray\t*URLarray;\r\n\tNSData\t\t\t*XMLdata;\r\n}\r\n@end<\/pre>\n<p>e creiamo i metodi getter e setter come abbiamo visto nella lezione precedente. (prometto che far\u00f2 un tutorial sull&#8217;uso di property..)<\/p>\n<p>Per i pi\u00f9 svogliati ecco il codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">- (void) setURLarray:(NSMutableArray *)anArray\r\n{\r\n\tURLarray = anArray;\r\n}\r\n\r\n- (NSMutableArray *)getURLarray\r\n{\r\n\treturn URLarray;\r\n}\r\n\r\n- (void) setXMLdata:(NSData *)data\r\n{\r\n\tXMLdata = data;\r\n}\r\n\r\n- (NSData *) getXMLdata\r\n{\r\n\treturn XMLdata;\r\n}<\/pre>\n<p>Direi di creare anche un metodo initWithXMLData che ci permetter\u00e0, quando utilizzeremo questa classe di inizializzarla e impostare il valore di XMLData in una sola istruzione.<br \/>\necco il codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">- (id)initWithXMLdata:(NSData *)data\r\n{\r\n\tif (self = [super init])\r\n    {\r\n\t\t[self setXMLdata:data];\r\n    }\r\n    return self;\r\n}<\/pre>\n<p>Restano da dichiarare i metodi veri e propri per il parsing del file xml, vi consiglio di leggere (se non l&#8217;avete ancora fatto) i tutorial a tal proposito che trovate su questo stesso sito,io dar\u00f2 per scontato che l&#8217;abbiate fatto, quindi vediamo e commentiamo subito il codice:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">- (NSMutableArray *) startParsing\r\n{\r\n\tNSXMLParser *feedParser = [[NSXMLParser alloc] initWithData:[self getXMLdata]];\r\n\t[feedParser setDelegate:self];\r\n\t[feedParser parse];\r\n\t[feedParser release];\r\n}<\/pre>\n<p>Questo \u00e8 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&#8217;oggetto per evitare memory leak.<br \/>\nForse \u00e8 il caso di specificare che cosa significhi impostare il delegate, perch\u00e9 \u00e8 un concetto fondamentale della programmazione MVC (model view controller) e quindi della programmazione per iphone.<br \/>\nAbbiamo gi\u00e0 parlato di delegate nell&#8217;articolo relativo <a href=\"http:\/\/www.devapp.it\/wordpress\/uipickerview-e-uidatepicker-guida-all-uso.html\" target=\"_blank\">all&#8217;UIPickerView<\/a>, e anche se parliamo di oggetti diversi la logica che ci sta dietro \u00e8 identica.<br \/>\nIn particolare l&#8217;oggetto NSXMLParser \u00e8 un parser <em>asincrono<\/em>, il che significa che una volta lanciata la procedura di parsing il codice non sta &#8220;fermo&#8221; ad aspettare che la procedura termini, sar\u00e0 il parser stesso ad inviare al proprio delegate specifici messaggi per informarlo di come procede il suo lavoro. Non si pu\u00f2 dire lo stesso per esempio del metodo<\/p>\n<pre>[NSData dataWithContentsOfURL:[NSURL URLWithString:fullAddress]];<\/pre>\n<p>che abbiamo utilizzato la scorsa lezione, questo metodo &#8220;blocca&#8221; l&#8217;esecuzione del codice fin quando non ha finito.<br \/>\nQuesta sar\u00e0 una informazione da tenere bene a mente nella creazione dell&#8217;interfaccia grafica, e lo vedremo bene nella prossima lezione.<br \/>\nIn pratica impostare il delegate per l&#8217;NSXMLParser significa &#8220;delegare&#8221; una classe a rispondere ai messaggi inviati da questo oggetto. Questo si traduce nell&#8217;implementare alcuni metodi che trovate specificati nella <em><a href=\"http:\/\/developer.apple.com\/mac\/library\/documentation\/cocoa\/reference\/NSXMLParserDelegate_Protocol\/Reference\/Reference.html\" target=\"_blank\">NSXMLParserDelegate Protocol Reference<\/a><\/em>, alcuni sono facoltativi, mentre altri sono obbligatori.<br \/>\nQuesto potrebbe essere chiamato &#8220;binding dinamico&#8221;, ovvero la possibilit\u00e0 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.<\/p>\n<p>Vediamo quindi quali sono i metodi che abbiamo deciso di implementare nel nostro delegate (il che significa anche &#8220;a quali messaggi del parser intendiamo rispondere&#8221;)<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\/\/INIZIA IL PROCESSO DI PARSING\r\n- (void) parserDidStartDocument:(NSXMLParser *)parser\r\n{\r\n\tNSLog(@\"PARSING STARTED\\n\");\r\n\t[self setURLarray:[NSMutableArray arrayWithCapacity:100]];\r\n}<\/pre>\n<p>Questo metodo viene invocato quando viene avviato il processo di parsing.<br \/>\nInizializziamo in questo momento l&#8217;array che conterr\u00e0 gli URL, poich\u00e9 per impostazione predefinita Flickr manda un file XML contenente le informazioni per recuperare 100 fotografie settiamo la dimensione del nostro array proprio a 100.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">- (void) parserDidEndDocument:(NSXMLParser *)parser\r\n{\r\n\tNSLog(@\"PARSING TERMINATO\\n\");\r\n\tif ([[self getURLarray] count] == 0) {\r\n\t\tNSLog(@\"ERRORE\");\r\n\t}\r\n}<\/pre>\n<p>Questo metodo viene invocato quando il parser termina il suo lavoro.<br \/>\nUtilizzo un paio di NSLog per verificare se il parsing \u00e8 andato a buon fine.<br \/>\nSe l&#8217;array con i link contiene zero elementi questo significa che c&#8217;\u00e8 stato un errore.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\/\/INIZIA IL RICONOSCIMENTO DI UN ELEMENTO\r\n- (void) parser:(NSXMLParser *)parser\r\ndidStartElement:(NSString *)elementName\r\n   namespaceURI:(NSString *)namespaceURI\r\n  qualifiedName:(NSString *)qName\r\n\t attributes:(NSDictionary *)attributeDict\r\n{\r\n\tif ([elementName isEqualToString:@\"photo\"]) {\r\n\t\t[[self getURLarray] addObject:[NSMutableString stringWithFormat:@\"http:\/\/farm%@.static.flickr.com\/%@\/%@_%@_m.jpg\",\r\n\t\t\t\t\t\t  [attributeDict objectForKey:@\"farm\"],\r\n\t\t\t\t\t\t  [attributeDict objectForKey:@\"server\"],\r\n\t\t\t\t\t\t  [attributeDict objectForKey:@\"id\"],\r\n\t\t\t\t\t\t  [attributeDict objectForKey:@\"secret\"]]];\r\n\t}\r\n}<\/pre>\n<p>Questo forse \u00e8 il metodo pi\u00f9 importante, viene invocato quando il parser riconosce l&#8217;inizio di un nuovo tag.<\/p>\n<div id=\"attachment_3591\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/06\/flickr_xml.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-3591\" class=\"size-full wp-image-3591\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/06\/flickr_xml.png\" alt=\"\" width=\"300\" height=\"278\" \/><\/a><\/p>\n<p id=\"caption-attachment-3591\" class=\"wp-caption-text\">File xml inviato da Flickr<\/p>\n<\/div>\n<p>Come possiamo vedere da questa immagine, il file XML fornito da Flickr \u00e8 costituito da un tag &#8220;RSP&#8221; che contiene l&#8217;esito della risposta, poi un tag &#8220;PHOTOS&#8221; che fornisce alcune indicazioni riguardo al numero di foto e di pagine (ricordo che c&#8217;\u00e8 la possibilit\u00e0 ri richiedere una specifica pagina o un numero specifico di foto anzich\u00e8 i valori di defaut) e poi un certo numero di tag &#8220;PHOTO&#8221; con tutti i dati delle fotografie.<br \/>\nNoi siamo interessati solo a quest&#8217;ultimo tag, ecco perch\u00e9 nel codice ho scritto<\/p>\n<pre>if ([elementName isEqualToString:@\"photo\"])<\/pre>\n<p>A questo punto possiamo costruire finalmente l&#8217;URL della foto, per fare questo costruiamo una stringa secondo le istruzioni fornite da flickr a questa pagina:\u00a0<a href=\"http:\/\/www.flickr.com\/services\/api\/misc.urls.html\" target=\"_blank\">http:\/\/www.flickr.com\/services\/api\/misc.urls.html<\/a><\/p>\n<p>Nel codice che ho scritto ho aggiunto &#8220;_m&#8221; perch\u00e9 voglio ottenere l&#8217;url della versione a grandezza media della foto.<br \/>\nCreato quindi l&#8217;url non resta che aggiungerlo all&#8217;array URLarray per scopi futuri.<\/p>\n<p>Come al solito chiediamo un p\u00f2 di gratificazione dopo tutto questo lavoro, vogliamo quantomeno vedere che cosa abbiamo ottenuto..<br \/>\nmodifichiamo quindi il file devFlickrViewController.m e modifichiamo il metodo ViewDidLoad in questo modo:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">- (void)viewDidLoad {\r\n    [super viewDidLoad];\r\n\tinterestingness *inter = [[interestingness alloc] initWithApiKey:@\"MY_API_KEY_IS_PRIVATE\"];\r\n\tNSData *tmp;\r\n\ttmp = [inter downloadXML];\r\n\tURLbuilder *urlBuilder = [[URLbuilder alloc] initWithXMLdata:tmp];\r\n\t[urlBuilder startParsing];\r\n\tNSLog(@\"%@\",[[urlBuilder getURLarray] description]);\r\n}<\/pre>\n<p>Eseguendo l&#8217;applicazione ed esaminando la console vedremo finalmente gli url delle foto.<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/06\/flickr_url.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-3592\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/06\/flickr_url-300x166.png\" alt=\"\" width=\"300\" height=\"166\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/06\/flickr_url-300x166.png 300w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/06\/flickr_url-150x83.png 150w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/06\/flickr_url.png 493w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Utilizzeremo questo array nella prossima lezione per visualizzare le foto nella nostra applicazione, questo ci permetter\u00e0 di affrontare il problema dei thread, quindi NON MANCATE!<\/p>\n<p style=\"text-align: center\"><a href=\"http:\/\/www.devapp.it\/wordpress\/supporto-applicazioni\/parole-vietate-di-ignazio-calo\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/02\/bannerIgnazioc.png\" alt=\"\" width=\"480\" height=\"100\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ed eccoci al terzo appuntamento, come avrete visto l&#8217;applicazione inizia prendere forma, la prima delle tre funzionalit\u00e0&#8230;<\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[240,238,241,226,223,224],"class_list":["post-3585","post","type-post","status-publish","format-standard","hentry","category-tutorial-pratici","tag-api-flickr","tag-flickr","tag-ignazio-calo","tag-nsxmlparser","tag-parsing-xml","tag-xml-iphone"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3585","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=3585"}],"version-history":[{"count":12,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3585\/revisions"}],"predecessor-version":[{"id":5017,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3585\/revisions\/5017"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=3585"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=3585"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=3585"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}