Tutorial pratici per iPhone SDK v1.6 - Get a Free Blog
Tutorial pratici per iPhone SDK v1.6 - Get a Free Blog
Tutorial pratici per iPhone SDK v1.6 - Get a Free Blog
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
INDICE<br />
Prefazione! 8<br />
Parte 1: tutorial di base! 9<br />
Capitolo 1: Introduzione al <strong>SDK</strong> e ad XCode! 10<br />
Introduzione! 10<br />
Panoramica sul <strong>SDK</strong>! 10<br />
XCode! 11<br />
Capitolo 2: Come creare un nuovo progetto! 15<br />
I template di XCode! 15<br />
Creare un nuovo progetto! 17<br />
Interface Builder! 17<br />
Capitolo 3: Il nostro primo progetto, He"oWorld!! 20<br />
Creiamo la struttura grafica! 20<br />
Definiamo gli elementi e le azioni! 21<br />
Scriviamo il codice necessario! 24<br />
Facciamo nascondere la tastiera! 25<br />
Capitolo 4: TrashApp, gestiamo le immagini! 27<br />
Definiamo l’applicazione! 27<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 3
Definiamo l’aspetto grafico.! 28<br />
Implementiamo il movimento del logo! 31<br />
Il ripristino del logo! 33<br />
Capitolo 5: UIToolbar e auto-rotazione! 35<br />
Definiamo l’applicazione! 35<br />
Definiamo l’aspetto grafico! 35<br />
Scriviamo il codice necessario! 38<br />
Capitolo: 6: NSTimer e UIProgressView! 41<br />
Definiamo l’applicazione! 41<br />
Definiamo l’aspetto grafico! 42<br />
Scriviamo il codice! 44<br />
Capitolo 7: AccessContact, accediamo a"a rubrica! 48<br />
Definiamo il progetto! 48<br />
Definiamo la struttura grafica! 49<br />
Scriviamo il codice necessario! 50<br />
Capitolo 8: Creiamo un mini browser con le UIWebView! 53<br />
Creiamo la struttura grafica! 53<br />
Definiamo i componenti e co"eghiamo le azioni! 54<br />
Scriviamo il codice <strong>per</strong> aprire la pagina desiderata! 56<br />
Capitolo 9: UITableView, gestiamo le tabe"e! 58<br />
Parte 1: creiamo e definiamo la tabe"a! 58<br />
Creiamo un nuovo progetto! 58<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 4
Inseriamo il codice necessario! 59<br />
Parte 2: Inseriamo alcune funzionalità! 62<br />
Permettiamo la cance"azione di una riga! 62<br />
Rendiamo le ce"e selezionabili! 63<br />
Parte 3: Implementiamo la ricerca! 65<br />
A$iungiamo il box di ricerca! 65<br />
Modifichiamo i metodi già esistenti! 66<br />
Implementiamo la ricerca! 68<br />
Capitolo 10: gestiamo più viste (file “.xib” multipli)! 71<br />
Creiamo un nuovo progetto! 71<br />
Definiamo la prima vista! 72<br />
Definiamo la “VistaDue”! 74<br />
Scriviamo il codice necessario! 75<br />
Capitolo 11: Come creare una TabBar Application! 78<br />
Parte 1: la struttura di base! 78<br />
Creiamo una TabBar “pulita”! 78<br />
Definiamo le due viste! 79<br />
Creiamo l’aspetto grafico de"e due viste! 80<br />
Impostiamo la TabBar! 83<br />
Parte 2: Inseriamo una NavigationBar! 87<br />
Creiamo un nuovo elemento <strong>per</strong> la TabBar! 87<br />
Definiamo l’aspetto del nuovo elemento! 89<br />
Implementiamo due viste di dettaglio! 92<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 5
Definiamo l’aspetto de"e due viste di dettaglio! 93<br />
Come richiamare le due viste via codice! 96<br />
Capitolo 12: XML! 99<br />
Cosa è XML?! 99<br />
XML nel <strong>SDK</strong> di <strong>iPhone</strong>! 101<br />
Creiamo la struttura grafica! 101<br />
Scriviamo il codice necessario! 103<br />
Capitolo 13: SQL! 108<br />
Definiamo un nuovo progetto! 108<br />
Definiamo la classe “Data”! 110<br />
Creiamo il database! 114<br />
Concludiamo l’applicazione! 118<br />
Parte 2: semplici applicazioni! 122<br />
Capitolo 14: Creiamo un semplice lettore di feed RSS! 123<br />
Creiamo un nuovo progetto! 123<br />
Definiamo le azioni del parser! 125<br />
Concludiamo l’applicazione! 128<br />
Un piccolo miglioramento! 129<br />
Capitolo 15: Creiamo un client <strong>per</strong> Twitter!! 132<br />
Parte 1: connettiamoci a Twitter! 132<br />
impostiamo la libreria “MGTwitterEngine”! 132<br />
Definiamo la vista di caricamento! 136<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 6
Creiamo la classe “Tweet”! 137<br />
Definiamo la classe “SampleTwitterClientViewContro"er”! 138<br />
Le$iamo la timeline! 140<br />
Parte 2: Creiamo la tabe"a con i tweet letti! 143<br />
Creiamo la ce"a <strong>per</strong>sonalizzata! 145<br />
Definiamo la classe de"a tabe"a! 149<br />
Completiamo l’applicazione! 151<br />
Parte 3: Il salvata$io dei dati! 157<br />
Gestiamo il caricamento / salvata$io dei dati! 159<br />
Capitolo 16: Realizziamo il nostro “Brushes”! 162<br />
Parte 1: Creiamo la tavola grafica! 162<br />
Creiamo un nuovo progetto! 162<br />
Definiamo l’aspetto grafico de"’applicazione! 163<br />
Definiamo i metodi necessari! 166<br />
Parte 2: Inseriamo i setta$i! 170<br />
A$iungiamo le impostazioni! 170<br />
Scriviamo il codice necessario! 174<br />
Inseriamo il salvata$io del disegno! 177<br />
Bibliografia! 181<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 7
Prefazione<br />
Questo libro racchiude tutti i tutorial che ho creato sulla programmazione <strong>per</strong> <strong>iPhone</strong> e iPod<br />
Touch. Non vuole essere un manuale esauriente o sostituirsi alla documentazione ufficiale Apple,<br />
ma solo uno strumento <strong>per</strong> chi è alle prime armi, oppure <strong>per</strong> chi vuole imparare qualcosa<br />
che ancora non sa.<br />
Troverete una serie di guide pratiche, da seguire passo <strong>per</strong> passo, commentate e spiegate, <strong>per</strong><br />
consentire a tutti di imparare e capire quello che viene fatto. Il libro è diviso in due sezioni: la<br />
prima vi presenterà dei tutorial sugli aspetti e sui componenti base della programmazione <strong>per</strong><br />
<strong>iPhone</strong>, mentre la seconda parte vi fornirà alcuni tutorial in cui verranno create delle semplici<br />
applicazioni complete, in modo che abbiate un quadro d’insieme generale.<br />
Ringrazio chiunque legga queste pagine, s<strong>per</strong>ando di potervi aiutare in un vostro scopo, sia lavorativo<br />
o <strong>per</strong> pura passione (come la mia).<br />
Ringrazio la mia fidanzata, che mi ha sempre sopportato e sostenuto, seppur non sappia niente<br />
di programmazione!<br />
Ringrazio Fabiano Confuorto, fondatore e amministratore di iSpazio, una stupenda community<br />
che mi ha fatto scoprire il mondo <strong>iPhone</strong>, e che mi ha dato l’opportunità di creare e pubblicare<br />
i miei primi tutorial.<br />
Ringrazio Steve Jobs, <strong>per</strong> aver creato il Mac e l’<strong>iPhone</strong>, cercando sempre la <strong>per</strong>fezione nelle cose.<br />
E ricordatevi, solo essendo curiosi e affamati è possibile scoprire e creare qualcosa di nuovo e<br />
veramente innovativo.<br />
“Siate affamati, siate fo"i.”<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 8
Parte 1:<br />
tutorial di base<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 9
Capitolo 1: Introduzione al <strong>SDK</strong> e ad XCode<br />
INTRODUZIONE<br />
Con il rilascio del firmware 2.0, Apple ha segnato una svolta nel settore mobile: non era mai<br />
stato così semplice sviluppare e vendere le proprie applicazioni. Per <strong>per</strong>mettere tutto ciò, Apple<br />
ha creato AppStore, uno spazio che si integra al già famoso e collaudato iTunes Store. Qualsiasi<br />
sviluppatore, indipendente o azienda già affermata, può pubblicare le proprie creazioni<br />
semplicemente acquistando una licenza annua, al prezzo di 99$ (79€ <strong>per</strong> noi europei). Quali<br />
sono i vanta$i legati a"’acquisto di una licenza? Sono molti, e valgono il prezzo da pagare. La cosa<br />
più importante è, come già detto, la possibilità di vendere le proprie applicazioni in AppStore.<br />
Ci sono, <strong>per</strong>ò, altri vantaggi: la possibilità di scaricare e installare le versioni beta dei nuovi<br />
firmware (<strong>per</strong> testare la compatibilità delle proprie applicazioni); la possibilità di installare i<br />
propri progetti anche sull’<strong>iPhone</strong> / iPod Touch direttamente da XCode (cosa che non è possibile<br />
senza licenza); l’accesso ad un forum specifico in cui saranno es<strong>per</strong>ti Apple a dare risposte e<br />
ad aiutare gli sviluppatori in difficoltà; la disponibilità di una documentazione più ampia e più<br />
dettagliata. Come vedete non si tratta di sciocchezze.<br />
Ma come si sviluppano le applicazioni? Il tutto è davvero molto semplice (in pieno stile Apple): con<br />
il firmware 2.0, infatti, è stato rilasciato un <strong>SDK</strong> (Software Development Kit) ufficiale, che<br />
integra tutti gli strumenti necessari <strong>per</strong> creare applicazioni e giochi <strong>per</strong> <strong>iPhone</strong> e iPod Touch.<br />
Questo <strong>SDK</strong> è liberamente scaricabile dall’iOS Dev Center<br />
(http://develo<strong>per</strong>.apple.com/devcenter/ios/index.action), previa registrazione gratuita (ma si<br />
può accedere alla sezione anche con il proprio account di iTunes). L’iOS Dev Center è l’area di<br />
Apple dedicata agli sviluppatori (ovviamente di applicazioni <strong>per</strong> <strong>iPhone</strong>), in cui si può trovare<br />
davvero tantissimo materiale molto utile: esempi con codice ben commentato, documentazione<br />
delle librerie, documenti teorici, video, e molto altro ancora.<br />
Come ho già detto, <strong>per</strong> pubblicare applicazioni in AppStore è necessario disporre della licenza<br />
ufficiale. Questo, <strong>per</strong>ò, non basta <strong>per</strong> vedere pubblicate le proprie creazioni: ogni applicazione,<br />
infatti, passa sotto il controllo di Apple, che decide se accettarle o meno. Le applicazioni presenti<br />
in AppStore, infatti, devono rispettare il contratto del <strong>SDK</strong>, che prevede alcune limitazioni:<br />
è vietato, ad esempio, duplicare funzioni già presenti nel S.O. dell’<strong>iPhone</strong> (come l’invio di<br />
SMS e MMS), oppure sono vietate applicazioni con contenuto a sfondo sessuale o violento.<br />
Non pensate, quindi, di poter ingannare Apple: c’è chi si è visto rifiutare la propria applicazione<br />
anche <strong>per</strong> una semplice icona.<br />
PANORAMICA SUL <strong>SDK</strong><br />
Dopo aver scaricato e installato l’<strong>SDK</strong> (un’immagine dmg di circa 3 GByte), troverete tutto il<br />
necessario <strong>per</strong> sviluppare nella cartella “/Develo<strong>per</strong>/Applications”. Gli strumenti (davvero molto<br />
potenti) che Apple mette a disposizione sono i seguenti:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 10
• Dashcode, è un utile tool con cui potremo creare pagine web, widget (anche <strong>per</strong> la Dashboard<br />
di Mac OS X) e altro;<br />
• Instruments, <strong>per</strong>mette di analizzare e valutare le prestazioni delle nostre applicazioni (in<br />
termini di consumo di memoria, impiego del processore, etc). È destinato, ovviamente, agli<br />
sviluppatori più es<strong>per</strong>ti.<br />
• Interface Builder, grazie a questa applicazione sarà davvero un gioco da ragazzi creare<br />
l’aspetto grafico dei nostri programmi. Potremo inserire qualsiasi tipo di oggetto (bottoni,<br />
label, viste) semplicemente trascinando gli oggetti nella nostra schermata.<br />
• Quartz Composer, è un tool che <strong>per</strong>mette di creare animazioni ed effetti grafici, da utilizzare<br />
poi in altri programmi.<br />
• XCode, è l’ambiente di sviluppo vero e proprio. Sarà qui, infatti, che andremo a creare i nostri<br />
progetti, scrivere il codice e compilare il tutto. È lo strumento, insieme ad Interface<br />
Builder, che utilizzeremo di più.<br />
XCODE<br />
Analizziamo, ora, come si presenta XCode. Aprendo un progetto (vedremo nel capitolo 2 come<br />
crearne un nuovo) otterremo la seguente schermata:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 11
Potete notare tre sezioni principali: a sinistra troviamo “Groups & Files”, in cui abbiamo tutti i<br />
file che compongono il nostro progetto. Troveremo, quindi, le classi, le immagini inserite, i<br />
framework utilizzati. A destra, invece, possiamo vedere l’editor del codice, che ci assisterà e ci<br />
<strong>per</strong>metterà di scrivere il nostro codice. La barra in alto, infine, ci offre la possibilità di compilare<br />
ed installare la nostra applicazione, sul dispositivo che preferiamo: il nostro <strong>iPhone</strong> (solo nel<br />
caso in cui abbiamo la licenza ufficiale) oppure l’<strong>iPhone</strong> Simulator (un simulatore che ci <strong>per</strong>metterà<br />
di testare le nostre applicazioni comodamente sul Mac, senza dover installare nulla sul<br />
nostro <strong>iPhone</strong>).<br />
Il menù a tendina presente a sinistra della barra ci <strong>per</strong>mette di scegliere velocemente alcune<br />
opzioni, molto utili in fase di compilazione ed installazione. Se lo apriamo troviamo le seguenti<br />
voci (che ovviamente variano a seconda della versione di <strong>SDK</strong> che avete installato nel vostro<br />
Mac):<br />
La prima parte ci <strong>per</strong>mette di scegliere se installare la nostra applicazione sul simulatore oppure<br />
su un device fisico. Ovviamente all’inizio del vostro progetto testerete l’applicazione solo sul<br />
simulatore, ma poi sarà molto importante controllare che tutto funzioni correttamente anche<br />
sul dispositivo vero e proprio.<br />
La seconda impostazione riguarda “Active Configuration”: selezionando l’opzione “Debug” otterremo<br />
un’applicazione più pesante, progettata <strong>per</strong> essere testata e corretta (proprio in quella<br />
che viene definita fase di debug); la versione “Release”, invece, è molto più leggera ed è pronta<br />
<strong>per</strong> essere rilasciata e pubblicata in AppStore.<br />
Se cliccate due volte sul nome del progetto si aprirà una finestra in cui vi verranno mostrate<br />
tutte le proprietà del vostro progetto. Alcune imparerete a conoscerle durante la lettura, altre<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 12
invece non le utilizzerete mai nella vostra vita (a meno che non andiate a lavorare al campus di<br />
Cu<strong>per</strong>tino di Apple, e ve lo auguro con tutto il cuore).<br />
Concentriamoci, <strong>per</strong>ò, su due voci importantissime. La prima è “Base <strong>SDK</strong>”, che trovate nelle<br />
prime posizioni:<br />
essa indica la versione dell’<strong>SDK</strong> che stiamo utilizzando. Se scaricate qualche progetto e vi appare<br />
la scritta “Base <strong>SDK</strong> Missing”, dovete semplicemente entrare in questa opzione e selezionare<br />
la vostra versione di <strong>SDK</strong>. Questa serve solamente <strong>per</strong> far capire ad XCode che stiamo<br />
lavorando con l’<strong>SDK</strong> di iOS, e non quello <strong>per</strong> Mac OS X.<br />
Un’altra opzione di fondamentale importanza la trovare un po’ più sotto, si chiama “iOS Deployment<br />
Target”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 13
Qui andremo a selezionare la versione del firmware con cui vogliamo che sia compatibile la nostra<br />
applicazione. Questo è necessario in quanto spesso, con il rilascio di nuovi firmware, vengono<br />
aggiunte anche nuove funzioni all’<strong>SDK</strong> (le API). Quindi, un’applicazione scritta e compilata<br />
<strong>per</strong> il firmware 4.2 potrebbe non funzionare con una versione inferiore del firmware (spesso<br />
è proprio impossibile installarla, in quanto l’AppStore controlla questa compatibilità in fase<br />
di installazione). Al contrario, se compiliamo l’applicazione <strong>per</strong> la versione 3.0 funzionerà sicuramente<br />
(a meno che non utilizziate delle API con alcuni bug) sulla 4.2. È importante, quindi,<br />
scegliere con cura la versione da utilizzare, <strong>per</strong> non escludere parte di utenza dall’utilizzo della<br />
nostra applicazione.<br />
Per ora è buona norma rendere le vostre applicazioni compatibili dal firmware 3.1 in su, in<br />
modo tale da non escludere nessun device (i primi <strong>iPhone</strong> EDGE e gli iPod Touch di 1° generazione,<br />
infatti, non possono installare iOS 4).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 14
Capitolo 2: Come creare un nuovo progetto<br />
Abbiamo dato un’occhiata al <strong>SDK</strong> e ad XCode. È venuto il momento di iniziare a vedere gli<br />
strumenti che XCode ci mette a disposizione <strong>per</strong> realizzare i nostri progetti.<br />
In questo capitolo vedremo come creare un nuovo progetto, quali template XCode ci mette a<br />
disposizione e le caratteristiche principali di Interface Builder.<br />
I TEMPLATE DI XCODE<br />
Avviando XCode e selezionando “File -> New Project...”, si aprirà la seguente finestra:<br />
Potete notare che XCode ci fornisce vari template, ovvero delle strutture già pronte, che ci<br />
<strong>per</strong>metteranno di creare applicazioni sullo stile di quelle native. Non dovremo <strong>per</strong>dere tempo,<br />
quindi, <strong>per</strong> replicare lo stile delle altre applicazioni, <strong>per</strong>ché è Apple stessa che ce li mette a disposizione.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 15
( Navigation-Based! ! Tab Bar Application! ! ! Utility Application<br />
Analizziamo, ora, i vari template che ci vengono forniti.<br />
• Navigation-Based Application, genera un’applicazione in cui possiamo navigare in sotto-livelli.<br />
Per farvi un esempio, pensate alla struttura di “Impostazioni” nel vostro <strong>iPhone</strong>: avete<br />
una barra in alto che visualizza il titolo della sezione corrente, e vi <strong>per</strong>mette, tramite un<br />
bottone, di tornare alla sezione precedente. Questa barra viene chiamata “Navigation Bar”.<br />
Utile <strong>per</strong> creare applicazioni con tabelle, in cui vogliamo mostrare anche le informazioni<br />
sui vari elementi.<br />
• OpenGL ES Application, questa è sicuramente la tipologia più complessa, in quanto si basa<br />
sulla tecnologia OpenGL (http://it.wikipedia.org/wiki/OpenGL), sfruttata principalmente<br />
<strong>per</strong> realizzare videogiochi o animazioni grafiche complesse. In questo libro non analizzeremo<br />
questa tipologia di applicazioni.<br />
• Tab Bar Application, fornisce un’applicazione con la “tab bar”, ovvero la barra nera composta<br />
da più sezioni (ad esempio quella che trovate nell’applicazione nativa “Musica”).<br />
• Utility Application, questa tipologia implementa un menù che viene richiamato ruotando la<br />
schermata principale. Anche in questo caso, potete trovare una similitudine con l’applicazione<br />
“Meteo”: se premete sulla “i” presente a fondo pagina, la schermata ruoterà e vi <strong>per</strong>metterà<br />
di modificare i settaggi dell’applicazione.<br />
• View-Based Application, fornisce un’applicazione vuota, senza nessuna implementazione<br />
particolare. Questo template è composto da una finestra, chiamata “MainWindow”, e una<br />
vista, “[nome_progetto]ViewController”, che viene caricata proprio dalla finestra principale.<br />
Sarà questo punto di partenza <strong>per</strong> tutti i nostri tutorial.<br />
• Window-Based Application, è molto simile al caso precedente, ma il template fornito è composto<br />
solamente da una finestra (non è presente quindi la vista “[nome_progetto]ViewController”).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 16
CREARE UN NUOVO PROGETTO<br />
In ogni tutorial che vedremo, sarà necessario creare un nuovo progetto. Per fare ciò, vi basterà<br />
aprire XCode, selezionare “File -> New Project...”, si aprirà la finestra con la scelta del template,<br />
che abbiamo appena analizzato. Scegliete il template desiderato (generalmente sarà View-<br />
Based Application), cliccate su “Choose..” e nel box successivo inserite il nome del nostro progetto.<br />
Finito!<br />
INTERFACE BUILDER<br />
Scorrendo la sezione “Groups & Files” possiamo vedere tutti i file che XCode ha già inserito<br />
<strong>per</strong> noi. Nel capitolo 3 vedremo come creare la nostra prima applicazione (il classico HelloWorld),<br />
ora ci limitiamo ad analizzare le caratteristiche principali dell’Interface Builder.<br />
Facciamo doppio clic su “[nome_progetto]ViewController.xib”, nella cartella “Resources”, e si<br />
aprirà Interface Builder.<br />
Ci ritroveremo con una situazione simile a questa:<br />
Potete notare vari strumenti sul vostro desktop: la libreria, la schermata della nostra applicazione<br />
(<strong>per</strong> ora completamente grigia), ed altri strumenti.<br />
Analizziamo ora questi componenti.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 17
• Library, è la libreria da cui possiamo inserire tutti gli oggetti che desideriamo. Se non è già<br />
a<strong>per</strong>ta, ci basterà andare in “Tools -> Library” e si aprirà<br />
una finestra come quella a lato. Scorrendo la barra laterale,<br />
potete notare moltissimi componenti, come bottoni,<br />
label di testo, viste, barre e molto altro. Tutti questi elementi<br />
potranno essere utilizzati nelle nostre applicazioni.<br />
Per inserirli basta trascinare un componente nella schermata<br />
dell’applicazione, e collocarlo a proprio piacere<br />
(questo è vero <strong>per</strong> tutti i componenti tranne i “Controllers”,<br />
che potrete riconoscere <strong>per</strong>ché hanno uno sfondo<br />
giallo).<br />
• Vista o finestra, è la nostra vista, ovvero la finestra che verrà visualizzata sull’<strong>iPhone</strong>. Potremo<br />
<strong>per</strong>sonalizzarla a nostro piacimento, e impareremo nei capitoli successivi come fare.<br />
L’unica cosa che vi faccio notare, è la freccia presente a destra del nome della vista:<br />
Se provate a cliccarla, noterete che la vista ruota: questo <strong>per</strong>ché sarà possibile implementare<br />
la possibilità di ruotare la nostra applicazione quando l’utente ruota il proprio <strong>iPhone</strong>.<br />
Vedremo in dettaglio questo aspetto in un tutorial successivo.<br />
• Panne"o documenti, questo pannello vi mostra tutti i componenti del vostro file xib. All’inizio<br />
vi potrà sembrareinutile, <strong>per</strong>ò quando l’applicazione<br />
inizierà a diventare complessa, vi sarà molto<br />
utile <strong>per</strong> ritrovare tutti i componenti della vostra<br />
finestra.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 18
• Inspector, è sicuramente la parte più importante di Interface Builder, in quanto ci <strong>per</strong>mette<br />
di impostare qualsiasi proprietà, relativa ad ogni oggetto (dalla vista al singolo bottone).<br />
Potremo, quindi, modificare l’aspetto degli oggetti, collegare le azioni, modificarne la dimensioni.<br />
Insomma, potrete agire su moltissimi aspetti (il tutto senza scrivere una riga di<br />
codice).<br />
L’Inspector è composto da 4 parti:<br />
✴Attributes, qui possiamo variare gli attributi generici dei nostri oggetti, ad esempio il<br />
colore, la dimensione del font, ed altre proprietà che impareremo poco alla volta.<br />
✴Connections, è uno dei pannelli principali. Qui andremo a collegare le azioni agli oggetti.<br />
Cosa significa? Ve lo spiego con un esempio. Supponiamo di avere un bottone<br />
nella nostra vista, e vogliamo che quando viene premuto venga scritto “Ciao” in una<br />
casella di testo. Creeremo, quindi, un’azione, che si occu<strong>per</strong>à di scrivere “Ciao”. Dovremo,<br />
poi, collegare questa azione al bottone, in modo che quando l’utente preme il<br />
bottone, viene eseguito il comportamento desiderato. Vedrete che con i prossimi tutorial<br />
tutto questo sarà più familiare.<br />
✴Size, questa sezione <strong>per</strong>mette, come dice la parola stessa, di modificare le dimensioni<br />
dell’oggetto, e di modificarne anche la posizione e l’ancoraggio (ovvero dove deve essere<br />
fissato, questo sarà fondamentale quando implementeremo la rotazione della<br />
schermata).<br />
✴Identity, in questo pannello sono presenti alcune voci relative al progetto e al file che<br />
stiamo modificando. Noi non utilizzeremo mai questo pannello, quindi potete anche<br />
non considerarlo.<br />
Abbiamo così completato la panoramica sull’Interface Builder. Mi pare inutile, <strong>per</strong> ora, dilungarmi<br />
in altri aspetti, che vi saranno sicuramente più chiari e familiari con un po’ di pratica. In<br />
pochissimo tempo, non riuscirete più a fare a meno di Interface Builder!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 19
Capitolo 3: Il nostro primo progetto, HelloWorld!<br />
In questo capitolo realizzeremo la nostra prima applicazione, il classico HelloWorld! Chiederemo<br />
all’utente il proprio nome (ad esempio Tizio) e alla pressione di un bottone faremo apparire<br />
il messaggio “Ciao Tizio”. Niente di complicato quindi, <strong>per</strong>ò cercate di capire bene tutti i<br />
passaggi, in modo da non avere lacune su queste cose basilari.<br />
CREIAMO LA STRUTTURA GRAFICA<br />
Iniziamo quindi creando un nuovo progetto di tipo “View-Based Application” e chiamiamolo<br />
“HelloWorld”. Apriamo quindi il file “HelloWorldViewController.xib”, che avvierà anche l’Interface<br />
Builder. Ora dobbiamo creare la struttura grafica, che deve essere simile a questa:<br />
Come potete osservare, ci sono tre componenti principali:<br />
1.una UITextField in cui l’utente potrà inserire il proprio nome;<br />
2.una UIButton, con la scritta “Saluta!”, che l’utente dovrà premere <strong>per</strong> far apparire il saluto;<br />
3.due UILabel, una con la scritta “Nome” (e questa serve solo <strong>per</strong> rendere più intuitivo il<br />
nostro programma), l’altra posta a centro schermo (che contiene la stringa Label). È importante<br />
impostare le dimensioni di questa ultima label in modo che occupi tutta la larghezza<br />
della vista, altrimenti avremo problemi quando andremo a stampare il messaggio di saluto<br />
in seguito.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 20
Tramite “Attribute Inspector” possiamo definire alcune proprietà <strong>per</strong> questi oggetti. Selezioniamo<br />
ad esempio la UITextField, e impostiamo i seguenti valori:<br />
• “Capitalize”: “Words” (ovvero quando l’utente inizia a digitare il proprio nome la prima lettera<br />
viene scritta in maiuscolo);<br />
• “Corrections”: “No” (disabilitiamo la correzione automatica <strong>per</strong> questo campo);<br />
• Spuntiamo l’opzione “Clear When Editing Begins” (cancellerà il contenuto già presente non<br />
appena l’utente seleziona il campo).<br />
A vostro piacere potete anche impostare altre proprietà, provatene alcune <strong>per</strong> prendere un po’<br />
più di confidenza.<br />
Prima di proseguire, diamo un’occhiata a ciò che compone questo file (lo potete trovare nel<br />
pannello dei documenti):<br />
Potete notare tre elementi, che XCode ha già definito <strong>per</strong> noi.<br />
• File’s Owner, come dice la parola stessa, è il proprietario del file. È, in sostanza, la classe che<br />
gestisce la nostra finestra, ovvero che gestisce ogni singolo aspetto. Nel nostro caso sarà la<br />
classe “HelloWorldViewController”, dove poi andremo a scrivere il codice necessario.<br />
• First Responder, <strong>per</strong> ora non è un componente che ci interessa, <strong>per</strong>ò sappiate che si occupa,<br />
ad esempio, della gestione del multi-touch.<br />
• View, è la nostra vista, ovvero la schermata che abbiamo definito. In questo caso ne abbiamo<br />
solo una, ma nulla ci vieta di definirne svariate e richiamarle poi a nostro piacimento.<br />
DEFINIAMO GLI ELEMENTI E LE AZIONI<br />
Dobbiamo ora definire gli elementi e le azioni necessarie. Il procedimento sarà sempre questo,<br />
ovvero definire gli elementi via codice e poi collegarli ad oggetti di Interface Builder. Salviamo<br />
tutto e chiudiamo Interface Builder, tornando così in XCode.<br />
Nella cartella “Classes” noteremo quattro file: due con estensione “.h” e due con estensione<br />
“.m”. I file “.h” stanno ad indicare le classi di intestazione, ovvero dove vengono definiti i me-<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 21
todi e i componenti necessari, ma non vi è alcuna implementazione dei metodi. Saranno i file<br />
con estensione “.m” a contenere tutte le implementazioni dei metodi, ovvero il codice delle varie<br />
funzioni.<br />
Iniziamo, quindi, aprendo il file “He"oWorldViewContro"er.h”, in cui dovremo definire gli oggetti<br />
che ci serviranno. Nel nostro esempio, saranno due gli elementi da definire: la UITextField in<br />
cui l’utente inserisce il proprio nome (e da cui noi dobbiamo leggerne il valore), e la UILabel in<br />
cui scriveremo il saluto. Dovremo, poi, definire un’azione, quella che verrà richiamata alla pressione<br />
del bottone.<br />
Ecco il codice da inserire:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
#import <br />
@interface HelloWorldViewController : UIViewController {<br />
! IBOutlet UITextField *fieldNome;<br />
! IBOutlet UILabel *labelSaluto;<br />
}<br />
-(IBAction)saluta;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet UITextField *fieldNome;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet UILabel *labelSaluto;<br />
@end<br />
Abbiamo dichiarato una UITextField e una UILabel, proprio i due componenti che ci servono.<br />
Possiamo notare che entrambe le dichiarazioni sono precedute dalla clausola “IBOutlet”, che<br />
indica ad Interface Builder che è possibile collegare questo metodo ad un elemento grafico.<br />
Questo è necessario <strong>per</strong>ché, come vedrete fra poco, ci <strong>per</strong>metterà di collegare l’oggetto creato<br />
tramite Interface Builder con quello dichiarato in XCode.<br />
Dopo queste due dichiarazioni, trovate l’intestazione del metodo “saluta”, e anche in questo<br />
caso trovate una clausola ”IBAction”: anche questa sta a significare che l’azione è collegata ad<br />
un componente di Interface Builder.<br />
Le due pro<strong>per</strong>ty, poi, servono <strong>per</strong> poter utilizzare senza problemi le proprietà degli oggetti che<br />
abbiamo definito.<br />
Ora salviamo il file (Cmd + S) e riapriamo “HelloWorldViewController.xib”. Dobbiamo collegare<br />
questi componenti con quelli effettivamente inseriti nella nostra vista.<br />
Dal pannello dei documenti selezionate il componente “File’s Owner”. Aprendo il “Connections<br />
Inspector” dovreste vedere un pannello come questo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 22
Potete notare che sono presenti i componenti che abbiamo definito via codice! Ora non dobbiamo<br />
fare altro che collegarli agli elementi adeguati. Prendiamo il pallino a fianco di “fieldNome”<br />
e trasciniamolo fino alla UITextField della nostra vista. Avremo così<br />
collegato i due elementi! Ripetiamo la stessa o<strong>per</strong>azione con “labelSaluto”,<br />
trascinando il pallino sulla UILabel posta a centro schermo.<br />
Stessa o<strong>per</strong>azione va eseguita <strong>per</strong> l’azione “saluta”. Collegatela al bottone, ma<br />
quando rilasciate il bottone del mouse vi apparirà un menù come quello che<br />
trovate qui a fianco.<br />
Sono tutte le azioni che può gestire un bottone. Noi selezioniamo “Touch<br />
Up Inside”, ovvero un azione di click e rialscio (un singolo tap insomma).<br />
Volendo potremmo scegliere di avviare l’azione quando il bottone viene rilasciato,<br />
ma <strong>per</strong> il nostro scopo non cambia niente.<br />
Se avete eseguito tutto correttamente avrete un pannello “Connections Inspector” come questo:<br />
Abbiamo così concluso la definizione dei componenti della nostra applicazione. Salviamo tutto<br />
e chiudiamo Interface Builder.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 23
SCRIVIAMO IL CODICE NECESSARIO<br />
Dobbiamo ora implementare il metodo “saluta”, che si occu<strong>per</strong>à di leggere il nome inserito dall’utente<br />
e stampare il messaggio di benvenuto sulla label predisposta.<br />
Apriamo il file “HelloWorldViewController.m” e inseriamo il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
26<br />
27<br />
#import "HelloWorldViewController.h"<br />
@implementation HelloWorldViewController<br />
// importiamo i componenti di cui abbiamo definito le pro<strong>per</strong>ty<br />
@synthesize fieldNome, labelSaluto;<br />
// azione richiamata alla pressione del bottone<br />
-(IBAction)saluta{<br />
! // leggiamo la stringa contenuta nella UITextField (il nome dell'utente)<br />
! NSString *nome = fieldNome.text;<br />
!<br />
! if ([nome length] == 0){<br />
! ! // l'utente non ha inserito nessun nome<br />
! ! labelSaluto.text = [[NSString alloc]<br />
initWithFormat:@"Ciao anonimo!"];<br />
! }else{<br />
! ! // salutiamo l'utente<br />
! ! labelSaluto.text = [[NSString alloc]<br />
initWithFormat:@"Ciao %@",nome];<br />
! }<br />
}<br />
- (void)dealloc {<br />
! [labelSaluto dealloc];<br />
! [fieldNome dealloc];<br />
!<br />
[su<strong>per</strong> dealloc];<br />
}<br />
Analizziamo il codice poco alla volta. L’istruzione presente alla riga 3 che ha il compito di caricare<br />
gli elementi di cui prima abbiamo definito le “pro<strong>per</strong>ty”. Potrebbe sembrare un po’ strana,<br />
ma <strong>per</strong> ora prendetela come regola.<br />
Dalla riga 9 alla 20 troviamo la definizione del metodo “saluta”. In tale metodo, non facciamo<br />
altro che leggere il nome inserito dall’utente (tramite “fieldNome.text”, che ci restituisce la<br />
stringa contenuta nella UITextField) e assegnarlo alla variabile “nome” (riga 11). Tramite una<br />
costrutto “if” (dalla riga 13 alla 19) andiamo poi a controllare se tale stringa è vuota (e quindi<br />
l’utente ha premuto il tasto senza inserire nessun nome) oppure se vi è un valore. Ovviamente<br />
inseriamo due messaggi di saluto diversi a seconda del caso.<br />
Particolare attenzione merita parte dell’istruzione alla riga 18, ed in particolare questo pezzo di<br />
codice: “@"Ciao %@",nome”.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 24
• “@”, la prima chiocciola sta ad indicare che ciò che segue è una stringa. La sintassi è sempre<br />
la stessa, è può essere schematizzata nel seguente modo: @”stringa_desiderata”. Dovrete<br />
sempre utilizzare questo formato quando istanziate una stringa.<br />
• “%@”, quando trovate un % in una stringa, significa che li ci andrà il valore di una determinata<br />
variabile. Non a caso dopo la stringa trovare la variabile “nome”: il contenuto di tale<br />
variabile nome andrà inserito al posto di %@. Se avessimo dovuto inserire il valore di una<br />
variabile di tipo float avremmo usato la sintassi %f. Vedremo parecchi esempi nei prossimi<br />
tutorial.<br />
Il metodo “dealloc”, infine, è quello che si occupa di liberare la memoria che abbiamo utilizzato.<br />
L’Objective-C, infatti, non prevede un gestore della memoria come avviene invece in Java<br />
(tramite il Garbage Collector). Sarà compito degli sviluppatori, quindi, liberare la memoria dagli<br />
oggetti che non servono più. In questo metodo dovrete sempre inserire i componenti che<br />
avete utilizzato, richiamando <strong>per</strong> ognuno il metodo “dealloc”. Nell’esempio potete vedere che<br />
liberiamo dalla memoria gli oggetti “labelSaluto” e “fieldNome”.<br />
Possiamo ora cliccare su “Build and Go!”, se non abbiamo commesso errori nell’inserire il codice<br />
si avvierà l’<strong>iPhone</strong> Simulator e potremo testare il nostro programma!<br />
FACCIAMO NASCONDERE LA TASTIERA<br />
Se provate ad inserire un nome e a premere il tasto “Invio” della tastiera che appare sull’<strong>iPhone</strong>,<br />
noterete che essa non si chiude. Si tratta di un bug? La risposta è no. È normale, in quanto<br />
non abbiamo implementato niente che chiuda tale tastiera.<br />
Per sistemare questo problema, apriamo il file “HelloWorldViewController.h” e modifichiamo<br />
l’intestazione nella seguente maniera:<br />
1 @interface HelloWorldViewController : UIViewController {<br />
Potete notare che abbiamo aggiunto ““, ovvero la nostra classe deve<br />
implementare il delegato della classe UITextField. Parleremo più avanti di cosa siano i delegati,<br />
<strong>per</strong> ora sappiate che sono dei comportamenti comuni a delle classi di oggetti.<br />
Fatto ciò, andiamo nel file “HelloWorldViewController.m” e inseriamo, in un qualsiasi punto,<br />
questo metodo:<br />
1<br />
2<br />
3<br />
4<br />
-(BOOL)textFieldShouldReturn:(UITextField *)textField{<br />
! [textField resignFirstResponder];<br />
! return YES;<br />
}<br />
Questo metodo si occu<strong>per</strong>à della chiusura della nostra tastiera. Non soffermiamoci sul codice,<br />
in quanto è così in qualsiasi occasione voi vogliate implementarlo. Salvate entrambi i file e aprite<br />
“HelloWorldViewController.xib”. Cliccate sulla UITextField e aprite il “Connections Inspector”:<br />
vedrete nella sezione “Outlets” un elemento chiamato “delegate”, prendete il pallino e<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 25
trascinatelo sul “File’s Owner” nel pannello dei documenti. Se avrete eseguito correttamente<br />
questa o<strong>per</strong>azione il vostro pannello sarà come questo:<br />
In pratica, abbiamo detto che il delegato di tale oggetto è gestito dalla classe “HelloWorld-<br />
ViewController”.<br />
Salvate ora il tutto e chiudete Interface Builder. Provate poi ad eseguire la vostra applicazione,<br />
tutto funzionerà in maniera corretta!<br />
Avete così creato la vostra prima applicazione funzionante <strong>per</strong> <strong>iPhone</strong>!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 26
Capitolo 4: TrashApp, gestiamo le immagini<br />
In questo secondo tutorial, inizieremo a prendere confidenza con un aspetto molto importante:<br />
la gestione delle immagini, e come l’utente può interagire con esse. Andremo a creare, infatti,<br />
un finto cestino, in cui potremo trascinare un’immagine e ripristinarla tramite un apposito<br />
pulsante.<br />
DEFINIAMO L’APPLICAZIONE<br />
Creiamo un nuovo progetto di tipo “View-Based Application” e chiamiamolo “TrashApp”. A<br />
differenza del tutorial precedente, questa volta creeremo tutto tramite Interface Builder, metodo<br />
sicuramente più veloce e comodo <strong>per</strong> applicazioni non troppo complesse.<br />
Prima di fare qualsiasi cosa, inseriamo nel nostro progetto le immagini che ci serviranno. Io<br />
utilizzerò le seguenti immagini: due <strong>per</strong> il cestino, e una <strong>per</strong> il documento da “eliminare” (potete<br />
trovare queste immagini nel file di progetto dell’esempio):<br />
TrashIconEmpty.png TrashIconFu".png windows icon.png<br />
Trascinate le immagini nel progetto in XCode, e nel pop-up che vi apparirà mettere la spunta a<br />
“Copy items into destination group’s folder (if needed)”. Noterete ora le immagini all’interno del progetto:<br />
Prima di definire la struttura grafica della nostra applicazione, andiamo a definire i componenti<br />
che poi ci serviranno. Apriamo il file “TrashAppViewController.h” e inseriamo le seguenti definizioni:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 27
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
#import <br />
@interface TrashAppViewController : UIViewController {<br />
! IBOutlet UIImageView *imageCestino;<br />
! IBOutlet UIImageView *imageLogo;<br />
}<br />
-(IBAction)ripristina;<br />
@end<br />
Abbiamo definito gli elementi necessari: alle righe 4 e 5 due UIImageView, che conterranno il<br />
cestino (pieno o vuoto a seconda del caso) e il logo da eliminare. Alla riga 8, infine, abbiamo<br />
definito l’azione che ci <strong>per</strong>metterà di ripristinare il logo dopo la sua eliminazione.<br />
DEFINIAMO L’ASPETTO GRAFICO.<br />
Procediamo, quindi, con la creazione della struttura grafica della nostra applicazione. Salvate il<br />
file “TrashAppViewController.h” appena modificato e aprite poi<br />
“TrashAppViewController.xib”, che avvierà Interface Builder.<br />
La finestra è <strong>per</strong> ora semplice e si presenterà così:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 28
Inseriamo, <strong>per</strong> prima cosa, gli elementi necessari: due componenti UIImageView e un UIButton.<br />
Attenzione: la prima UIImageView che inserite deve essere quella in basso, altrimenti<br />
avrete problemi nelle fasi successive! Ecco come si presenterà la vostra applicazione:<br />
Ora dobbiamo collegare i vari componenti alle immagini che abbiamo inserito all’inizio del<br />
progetto. Clicchiamo sul primo componente UIImageView (quello più in alto, ma il secondo<br />
che avete inserito!) e apriamo il pannello “Attributes Inspector”. Nel menù a tendina “Image”<br />
selezioniamo il file “windows icon.png” e lo vedremo comparire anche nell’applicazione. Spuntiamo,<br />
inoltre, la casella “User Interaction Enabled”. Avremo un pannello così impostato:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 29
Facciamo la stessa cosa <strong>per</strong> la UIImageView sottostante, selezionando come immagine<br />
“TrashIconEmpty.png”, ma senza spuntare “User Interaction Enabled”. Inseriamo all’interno<br />
del bottone la scritta “Ripristina logo”, aggiustiamo le dimensioni e la posizione delle due immagini<br />
(in modo che i bordi delle UIImageView coincidano con le immagini al loro interno)<br />
fino ad avere un risultato come questo:<br />
Ora non dobbiamo fare alto che collegare gli elementi che abbiamo definito all’inizio di questo<br />
tutorial con i componenti all’interno della nostra applicazione.<br />
Dal Pannello dei Documenti selezioniamo il “File’s Owner”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 30
Ora apriamo il “Connections Inspector”, dovremmo vedere i seguenti elementi:<br />
Prendiamo il pallino che troviamo a fianco di “imageLogo” e trasciniamolo sul logo di Windows,<br />
mentre quello di “imageCestino” sull’immagine del cestino.<br />
Colleghiamo, infine, l’azione: proprio come nello scorso tutorial, colleghiamo il pallino dell’azione<br />
“ripristina:” sul bottone, e nel menù che appare selezioniamo “Touch Up Inside”. Se<br />
abbiamo eseguito tutto in maniera corretta avremo un pannello come il seguente:<br />
Abbiamo concluso questa fase del tutorial. Salviamo tutto e chiudiamo pure Interface Builder.<br />
IMPLEMENTIAMO IL MOVIMENTO DEL LOGO<br />
Iniziamo aprendo il file “TrashAppViewController.h” e dichiarando un paio di elementi che ci<br />
serviranno:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 31
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
#import <br />
@interface TrashAppViewController : UIViewController {<br />
! IBOutlet UIImageView *imageCestino;<br />
! IBOutlet UIImageView *imageLogo;<br />
!<br />
! BOOL cancellato;<br />
}<br />
-(IBAction)ripristina;<br />
-(void)cancella;<br />
Alla riga 7 abbiamo aggiunto una variabile che ci servirà <strong>per</strong> controllare se il nostro oggetto è<br />
già stato eliminato (quindi, al valore YES corrisponderà il logo eliminato, con NO il nostro logo<br />
sarà ancora visibile); lo stesso vale <strong>per</strong> il metodo “cancella”, che si occu<strong>per</strong>à invece dell’animazione<br />
legata all’eliminazione del logo.<br />
Ora iniziamo ad implementare i metodi necessari. Apriamo il file “TrashAppViewController.m”<br />
e inseriamo il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
26<br />
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {<br />
! UITouch *touch = [[event allTouches] anyObject];<br />
! if ([touch view] == imageLogo) {<br />
! ! imageLogo.center = [touch locationInView:self.view];!<br />
! }! !<br />
}<br />
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {<br />
! if (CGRectIntersectsRect([imageCestino frame], [imageLogo<br />
frame])){<br />
! ! imageCestino.image = [UIImage<br />
imageNamed:@"TrashIconFull.png"];<br />
! ! [self cancella];<br />
! } else{<br />
! ! [UIView beginAnimations:nil context:NULL];<br />
! ! [UIView setAnimationDuration:0.5];<br />
! ! imageLogo.center=CGPointMake(155.0,100.0);<br />
! ! [UIView commitAnimations];<br />
! }<br />
}<br />
- (void)cancella{<br />
! cancellato = YES;<br />
! [UIView beginAnimations:nil context:NULL];<br />
! [UIView setAnimationDuration:0.5];<br />
! imageLogo.transform = CGAffineTransformMakeScale(.001, .001);<br />
! [UIView commitAnimations];<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 32
Abbiamo definito tre metodi, che si occu<strong>per</strong>anno del movimento del logo di Windows e della<br />
sua cancellazione. vediamoli nel dettaglio:<br />
• touchesMoved, (dalla riga 1 alla 6) In questo metodo, salviamo nella variabile “touch”<br />
l’evento che l’utente compie toccando un qualsiasi oggetto della nostra applicazione (riga<br />
2). Controlliamo, poi, che l’oggetto toccato corrisponda a “imageLogo” (riga 3), cioè al logo<br />
di Windows: se l’oggetto è proprio quello, teniamo traccia del centro dell’oggetto (che nel<br />
frattempo viene mosso dall’utente) con la posizione del dito sullo schermo (riga 4). Ovvero,<br />
è come se spostassimo fisicamente l’oggetto con il nostro dito e lo muovessimo su un piano.<br />
• touchesEnded, (dalla riga 8 alla 18) In questo metodo diciamo semplicemente che se il<br />
frame di “imageLogo” (ovvero il logo di Windows) interseca il frame del cestino (riga 9),<br />
deve essere chiamato il metodo “cancella”, che si occu<strong>per</strong>à dell’animazione della cancellazione<br />
(riga 11). Prima di chiamare tale metodo, inoltre, cambiamo l’immagine del cestino<br />
vuoto con quella del cestino pieno (riga 10). Se il logo, invece, non è stato spostato sopra il<br />
cestino, eseguiamo una semplice animazione, che riporta l’immagine al centro della vista<br />
(dalla riga 13 alla 16).<br />
• cancella, (dalla riga 20 alla 26) In questo metodo definiamo l’animazione che avrà il logo di<br />
Windows quando verrà sposato sopra il cestino. Alla riga 21 cambiamo il valore della variabile<br />
“cancella”, in modo da sa<strong>per</strong>e che il logo è stato eliminato. Alla riga 22 definiamo il<br />
punto di partenza della nostra animazione, mentre con l’istruzione successiva ne definiamo<br />
la durata. La riga 24 è l’animazione vera e propria, che farà scomparire il logo. Con l’ultima<br />
istruzione definiamo la fine dell’animazione.<br />
IL RIPRISTINO DEL LOGO<br />
Abbiamo quasi terminato la nostra applicazione, manca solo la definizione dell’azione “ripristina:”.<br />
Tale metodo è già stato definito da Interface Builder, quindi noi dobbiamo solo scrivere il<br />
codice al suo interno. Ecco le istruzioni da inserire:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
- (IBAction)ripristina{<br />
! if (cancellato) {<br />
! ! [UIView beginAnimations:nil context:NULL];<br />
! ! [UIView setAnimationDuration:0.5];<br />
! ! imageLogo.transform = CGAffineTransformIdentity;<br />
! ! imageCestino.image = [UIImage<br />
imageNamed:@"TrashIconEmpty.png"];<br />
! ! imageLogo.center = CGPointMake(155.0, 100.0);<br />
! ! [UIView commitAnimations];<br />
! ! cancellato = NO;<br />
! }<br />
}<br />
Questo metodo è speculare a “cancella”, in quanto dobbiamo eseguire l’animazione inversa!<br />
Andremo, quindi, ad eseguire un’animazione, che porterà il logo dal cestino (in cui si trova) alla<br />
posizione originale (o quasi, in quanto è definita in modo arbitrario da noi, alla riga 7).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 33
Clicchiamo ora su “Build and Go!”, e testiamo la nostra applicazione funzionante!<br />
Nota: se non avete l’animazione, controllate che il logo di Windows non si nasconda dietro il<br />
cestino. Se così fosse, non avete seguito quello che vi ho detto nella costruzione dell’Interfaccia!!<br />
Ma non dis<strong>per</strong>ate, vi basterà entrare in Interface Builder, selezionare la UIImageView con<br />
il logo di Windows e dal menù “Layout” cliccare su “Send Forward” (in alternativa dovete<br />
scambiare l’ordine dei due componenti, ovviamente invertendo anche le immagini e le proprietà<br />
associate).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 34
Capitolo 5: UIToolbar e auto-rotazione<br />
In questo terzo tutorial, analizzeremo un componente molto importante, la UIToolbar, e una<br />
funzionalità molto gradita agli utenti, l’auto-rotazione.<br />
Non creeremo nessuna applicazione complicata, semplicemente avremo due pulsanti nella<br />
toolbar che modificheranno il valore di una label posta al centro dello schermo. L’auto-rotazione,<br />
infine, aggiungerà un tocco più professionale alla nostra applicazione.<br />
DEFINIAMO L’APPLICAZIONE<br />
Come sempre, la prima cosa che faremo è definire un nuovo progetto. Creiamo un nuovo progetto<br />
di tipo “View-Based Application” e chiamiamolo “CountRotateApp”. Procediamo proprio<br />
come abbiamo fatto nello scorso tutorial, quindi apriamo il file<br />
“CountRotateAppViewController.h” e inseriamo le seguenti dichiarazioni:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
#import <br />
@interface CountRotateAppViewController : UIViewController {<br />
! IBOutlet UILabel *labelNumero;<br />
}<br />
-(IBAction)aggiungi;<br />
-(IBAction)sottrai;<br />
@end<br />
Abbiamo definito una label, che ospiterà un numero, che sarà incrementato o decrementato in<br />
base al pulsante che verrà premuto (ovviamente saranno le azioni “aggiungi” e “sottrai” che si<br />
occu<strong>per</strong>anno di questo compito).<br />
Salviamo il file appena modificato e facciamo doppio clic su<br />
“CountRotateAppViewController.xib”, in cui andremo a definire l’aspetto della nostra applicazione.<br />
DEFINIAMO L’ASPETTO GRAFICO<br />
Iniziamo inserendo nella parte bassa della vista una UIToolbar, con due UIBarButtonItem: in<br />
uno scrivete “-”, nell’altro “+”. Noterete che i due bottoni sono quasi attaccati. Noi vogliamo<br />
che siano ai due estremi, quindi tra di essi inseriamo un “Flexible Space Bar Button Item”, in<br />
modo che restino sempre separati. Ecco come si presenterà la vostra toolbar:<br />
Questo spazio flessibile ha una grossa utilità: non solo ci separa i due bottoni, ma ci <strong>per</strong>mette<br />
di non doverci occupare della giusta distanza tra essi, anche nel caso che ne aggiungessimo un<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 35
terzo. Inoltre esso ci <strong>per</strong>mette di tenere i due bottoni alle estremità della barra anche nel caso<br />
in cui ruotassimo la nostra applicazione. Come facciamo a testarlo? Semplice. Cliccate sulla<br />
freccia presente nel titolo della finestra della nostra applicazione:<br />
Vedrete che la schermata ruoterà!<br />
E come possiamo notare i due bottoni restano agli estremi della nostra barra. Proprio il risultato<br />
che volevamo!<br />
Riportiamo la finestra alla sua posizione originale, e inseriamo al centro una UILabel, partendo<br />
da un angolo in alto a sinistra, <strong>per</strong> poi ingrandirla fino all’angolo opposto. Nell’Attribute Inspector<br />
settate i seguenti parametri:<br />
• “Text”: 0 (zero);<br />
• A"ineamento centrale;<br />
• “Font Size”: 200<br />
Dovreste avere il seguente risultato:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 36
Proviamo ora a far ruotare la schermata come abbiamo fatto poco fa. Noteremo che lo zero<br />
non rimane in posizione centrale, ma addirittura viene <strong>per</strong> metà nascosto. Come facciamo a<br />
lasciarlo centrato? Anche qui ci viene in aiuto l’Interface Builder, che offre grandi potenzialità<br />
anche in questo aspetto.<br />
Selezioniamo la label che contiene lo zero e apriamo il “Size Inspector”. Nella seconda parte<br />
possiamo vedere che vi è una sezione denominata “Autosizing”. Clicchiamo sulle due freccette<br />
rosse che vediamo nel riquadro piccolo, in modo da avere questo schema:<br />
Proviamo ora a ruotare la nostra applicazione: lo zero resterà <strong>per</strong>fettamente in posizione centrale!<br />
Ora che abbiamo definito la struttura grafica dell’applicazione, non ci resta altro che collegare<br />
l’elemento e le due azioni che abbiamo definito all’inizio del tutorial.<br />
Dal Pannello dei Documenti selezioniamo il File’s Owner e spostiamoci poi nel “Controller<br />
Connections” (come abbiamo già fatto nel capitolo 4). Dovete avere un pannello come questo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 37
Colleghiamo “labelNumero” con l’unica label presente al centro della vista, e le due azioni ai<br />
rispettivi bottoni (al bottone “+” l’azione “aggiungi”, mentre al bottone “-” l’azione “sottrai”).<br />
Se avete eseguito tutto in maniera corretta avrete questo risultato:<br />
Salviamo tutto e chiudiamo Interface Builder.<br />
SCRIVIAMO IL CODICE NECESSARIO<br />
Prima di iniziare ad implementare i metodi che abbiamo già definito, aggiungete questa variabile<br />
al file “CountRotateAppViewController.h”:<br />
1<br />
2<br />
3<br />
4<br />
@interface CountRotateAppViewController : UIViewController {<br />
! IBOutlet UILabel *labelNumero;<br />
! int numero;<br />
}<br />
Semplicemente, abbiamo definito una variabile intera alla riga 3, di nome “numero”, che conterrà<br />
il valore mostrato dalla label.<br />
Passiamo, quindi, al file “CountRotateAppViewController.m”.<br />
Iniziamo con questo semplice metodo (dovreste trovarlo già presente nella classe, vi basterà<br />
eliminare i commenti che lo rendono nascosto):<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 38
1<br />
2<br />
3<br />
4<br />
- (void)viewDidLoad {<br />
! [su<strong>per</strong> viewDidLoad];<br />
! numero = 0;<br />
}<br />
Questo metodo viene richiamato sempre all’avvio del file “.xib” associato alla classe (i file “.xib”<br />
sono quelli creati da InterfaceBuilder). In questo metodo possiamo inizializzare tutti i componenti<br />
che ci serviranno. Qui, in pratica, dobbiamo inserire tutte quelle o<strong>per</strong>azioni che vogliamo<br />
vengano eseguite all’avvio dell’applicazione. Nel nostro esempio, vogliamo che la variabile<br />
“numero” sia impostata a zero. Prendete confidenza con tale metodo <strong>per</strong>chè lo incontrerete<br />
spesso nei prossimo tutorial.<br />
Aggiungiamo, ora, le implementazioni <strong>per</strong> i due metodi che si occupano di aumentare e diminuire<br />
il valore della variabile “numero”:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
- (IBAction)aggiungi {<br />
! numero++;<br />
! labelNumero.text = [[NSString alloc]<br />
initWithFormat:@"%i",numero];<br />
}<br />
- (IBAction)sottrai {<br />
numero--;<br />
! labelNumero.text = [[NSString alloc]<br />
initWithFormat:@"%i",numero];<br />
}<br />
Questo due metodi non eseguono niente di complesso, si limitano a incrementare (o decrementare)<br />
la variabile “numero”, <strong>per</strong> poi visualizzarla nella label. Semplice vero?<br />
L’ultima cosa da implementare è la rotazione della vista. Sempre nel file<br />
“CountRotateAppViewController.m” cercate e decommentate il seguente metodo (è già presente,<br />
vi basterà decommentarlo e modificare l’istruzione alla riga 3):<br />
1<br />
2<br />
3<br />
4<br />
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientatio<br />
n)interfaceOrientation {<br />
// Return YES for supported orientations<br />
return YES;<br />
}<br />
Questo è un metodo della classe “UIViewController”, che implementa già la rotazione automatica<br />
dello schermo. Ancora una volta non dovremo fare veramente niente, in quanto sono le<br />
librerie del <strong>SDK</strong> a fornirci tutti pronto.<br />
Piccola nota: se non volessimo implementare l’auto-rotazione, ci basterebbe ritornare come<br />
valore “NO”, oppure semplicemente non inserire il metodo nell’applicazione.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 39
Clicchiamo ora su “Build and Go!” e testiamo la nostra applicazione!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 40
Capitolo: 6: NSTimer e UIProgressView<br />
Proseguiamo la panoramica sui componenti più utilizzati nella creazione di applicazioni <strong>per</strong><br />
<strong>iPhone</strong>. In questo capitolo vedremo come utilizzare la classe NSTimer, ovvero un temporizzatore,<br />
che ci <strong>per</strong>metterà di eseguire animazioni e transizioni con durate predefinite. Utilizzeremo,<br />
inoltre, la UIProgressView, ovvero la barra di progresso, necessaria quando si deve mostrare<br />
un caricamento.<br />
Quella che andremo a creare sarà una semplice applicazione, che <strong>per</strong>metterà all’utente di cambiare<br />
il colore dello sfondo, semplicemente cliccando su un bottone. Il cambio del colore, inoltre,<br />
avverrà in maniera graduale tramite un’animazione della durata di 10 secondi.<br />
DEFINIAMO L’APPLICAZIONE<br />
Come sempre, iniziamo creando un progetto di tipo “View-Based Application” e chiamiamolo<br />
“ProgressColour”.<br />
Apriamo il file “ProgressColourViewController.h” e definiamo i seguenti componenti:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
#import <br />
@interface ProgressColourViewController : UIViewController {<br />
! IBOutlet UILabel *progressLabel;<br />
! IBOutlet UIProgressView *progressBar;<br />
!<br />
! IBOutlet UIButton *bottoneBlu;<br />
! IBOutlet UIButton *bottoneRosso;<br />
}<br />
- (IBAction)caricamentoColore:(id)bottone;<br />
@end<br />
La label definita alla riga 4 servirà <strong>per</strong> mostrare un messaggio all’utente sul grado di completamento<br />
dell’animazione, mentre la UIProgressBar darà la stessa informazioni ma in maniera più<br />
visiva (è una classica barra di caricamento). Abbiamo, inoltre, dichiarato anche due bottoni<br />
UIButton: vedremo, poi, il <strong>per</strong>chè di questa dichiarazione.<br />
L’azione alla riga 11 verrà associata ad entrambi i bottoni, infatti sarà questo metodo ad avviare<br />
il cambio di colore dello sfondo. Nell’intestazione di questo metodo c’è anche un parametro<br />
“bottone” di tipo “id”: questo ci servirà <strong>per</strong> determinare quale bottone ha invocato il metodo,<br />
in modo da poter caricare il colore scelto dall’utente.<br />
Possiamo ora iniziare a definire l’aspetto grafico dell’applicazione, aprendo il file<br />
“ProgressColourViewController.xib”.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 41
DEFINIAMO L’ASPETTO GRAFICO<br />
Inseriamo nella nostra vista i primi due componenti necessari: una UILabel e una UIProgressView.<br />
Ricreate una disposizione simile a questa (ovviamente nessuno vi vieta di <strong>per</strong>sonalizzarla<br />
a vostro piacimento):<br />
Come potete notare la label e la barra di progresso occupano quasi <strong>per</strong> intero la larghezza della<br />
vista, questo <strong>per</strong> rendere più evidente ciò che avviene.<br />
Selezioniamo la label e apriamo “Attributes Inspector”, <strong>per</strong> modificare alcune proprietà:<br />
• cancellate il contenuto del campo “Text”;<br />
• “Font Size”: 20<br />
• allineamento centrale.<br />
Selezioniamo ora la UIProgressView e, sempre in “Attributes Inspector”, impostiamo il valore<br />
della casella “Progress” a zero.<br />
Inseriamo ora nella vista due bottoni, in modo da avere un risultato finale come questo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 42
Abbiamo già concluso la creazione della parte grafica della nostra applicazione. Non ci resta<br />
che collegare i componenti che abbiamo definito ad inizio tutorial.<br />
Dal Pannello dei Documenti selezioniamo, come sempre, il “File’s Owner” e apriamo il “Connections<br />
Inspector”. Dovreste avere un pannello così composto:<br />
Colleghiamo l’elemento “progressLabel” con la label vuota presente sopra la barra, e “progressBar”<br />
con la barra stessa. Colleghiamo anche gli elementi “bottoneBlu” e “bottoneRosso”<br />
con i due relativi pulsanti. Colleghiamo, infine, l’azione “caricamentoColore” con entrambi i<br />
bottoni, selezionando “Touch Up Inside” dal menù a tendina che si presenta. Se avete eseguito<br />
tutto in maniera corretta dovreste avere questo risultato:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 43
Abbiamo così terminato questa fase. Salviamo e chiudiamo Interface Builder.<br />
SCRIVIAMO IL CODICE<br />
Dobbiamo definire due elementi e un paio di metodi che non abbiamo scritto inizialmente.<br />
Apriamo il file “ProgressColourViewController.h” e inserite le dichiarazioni mancanti:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
#import <br />
@interface ProgressColourViewController : UIViewController {<br />
! IBOutlet UILabel *progressLabel;<br />
! IBOutlet UIProgressView *progressBar;<br />
!<br />
! IBOutlet UIButton *bottoneBlu;<br />
! IBOutlet UIButton *bottoneRosso;<br />
!<br />
! NSTimer *timer;<br />
! UIColor *colore;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSTimer *timer;<br />
@pro<strong>per</strong>ty (nonatomic, retain) UIColor *colore;<br />
- (IBAction)caricamentoColore:(id)bottone;<br />
- (void)aggiornaColore ;<br />
- (void)applicaColore ;<br />
@end<br />
Abbiamo definito un componente “NSTimer” (alla riga 10), che sarà il temporizzatore che ci<br />
<strong>per</strong>metterà di eseguire l’animazione prevista. Nella riga successiva è definito un elemento UI-<br />
Color, che servirà <strong>per</strong> tener traccia del colore che deve essere applicato allo sfondo.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 44
Sono stati dichiarati, inoltre, due nuovi metodi, che ci serviranno <strong>per</strong> implementare le azioni<br />
necessarie (righe 18 e 19).<br />
Passiamo ora al file “ProgressColourViewController.m” e iniziamo ad implementare i metodi<br />
necessari. Inseriamo il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
#import "ProgressColourViewController.h"<br />
@implementation ProgressColourViewController<br />
@synthesize timer;<br />
@synthesize colore;<br />
- (IBAction)caricamentoColore:(id)bottone {<br />
! progressBar.progress = 0.0;<br />
! if (bottone == bottoneBlu){<br />
! ! progressLabel.text = @"Caricamento colore blu...";<br />
! ! colore = [UIColor blueColor];<br />
! }else if (bottone == bottoneRosso) {<br />
! ! progressLabel.text = @"Caricamento colore rosso...";<br />
! ! colore = [UIColor redColor];<br />
! }<br />
! timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self<br />
selector:@selector(aggiornaColore) userInfo:nil repeats:YES];<br />
}<br />
Questo metodo si occupa di avviare il caricamento del colore scelto dall’utente. Alla riga 9 viene<br />
settato il valore di progresso della barra a zero (tale valore di default va da 0.0 a 1.0, ma questo<br />
intervallo può essere modificato a piacere). Troviamo, poi, un controllo sul bottone che ha<br />
invocato il metodo (riga 10): se il bottone premuto dall’utente è quello <strong>per</strong> il colore blu, impostiamo<br />
la label indicando che viene caricato il blu, e assegniamo alla variabile “colore” il valore<br />
“[UIColor blueColor]”. Questo è un elemento predefinito della classe UIColor, che ci <strong>per</strong>mette<br />
di utilizzare colori standard in maniera semplice e veloce. Nello stesso modo lavora la clausola<br />
“else if”, ovviamente controllando se il bottone premuto è quello <strong>per</strong> il colore rosso.<br />
Alla riga 17, infine, viene definita la variabile timer, istanziandola con la classe NSTimer. Ci sono<br />
tre parametri molto importanti in questa funzione: la durata di 1 secondo (alla clausola<br />
“scheduledTimerWithTimeInterval”), il metodo che deve essere eseguito ad ogni ripetizione<br />
(clausola “@selector()”) e la ripetizione continua di tale intervallo di tempo (impostata tramite<br />
“repeats:YES“).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 45
Proseguiamo con la definizione dei metodi:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
- (void)aggiornaColore {<br />
! progressBar.progress = progressBar.progress + 0.1;<br />
! if (progressBar.progress == 0.5){<br />
! ! progressLabel.text = @"Applicando colore…";<br />
! ! [self applicaColore];<br />
! }<br />
! if (progressBar.progress == 1.0){<br />
! ! progressLabel.text = @"Colore applicato!";<br />
! ! [timer invalidate];<br />
! }<br />
}<br />
Alla riga 2 incrementiamo il valore della nostra barra di progresso, aumentandone il valore del<br />
10%. Alla riga 3 troviamo un controllo if, che verifica se il valore della barra è 0.5 (ovvero siamo<br />
a metà): in caso affermativo, cambiamo il testo presente nella label, altrimenti lasciamo tutto<br />
invariato. Anche alla riga 7 un ciclo if controlla se la barra di progresso è arrivata al suo valore<br />
massimo: in tal caso inseriamo un nuovo testo nella label, e fermiamo il timer (con l’istruzione<br />
alla riga 9).<br />
Nel primo ciclo if che abbiamo esaminato, notiamo che alla riga 5 viene richiamato il metodo<br />
“applicaColore”: tale metodo avrà il compito di cambiare il colore allo sfondo della vista, con<br />
un’animazione che dovrà durare 5 secondi (infatti siamo al 50% del progresso, e la barra avanza<br />
del 10% ogni secondo). Ecco tale metodo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
- (void)applicaColore {<br />
! [UIView beginAnimations:nil context:NULL];<br />
! [UIView setAnimationDuration:5.0];<br />
! self.view.backgroundColor = colore;<br />
! [UIView commitAnimations];<br />
}<br />
In questi due metodi viene definita l’animazione che <strong>per</strong>mette allo sfondo della nostra vista di<br />
cambiare colore. L’animazione rispecchia molto quella illustrata in un capitolo precedente.<br />
Alla riga 3 definiamo la durata di tale animazione (5 secondi); l’istruzione successiva è il risultato<br />
che vogliamo ottenere, ovvero il nostro colore di sfondo. Chiude il gruppo di istruzioni la<br />
riga 5, che avvia l’animazione.<br />
Clicchiamo su “Build and Go!” e testiamo la nostra applicazione!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 46
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 47
Capitolo 7: AccessContact, accediamo alla rubrica<br />
In questo capitolo andremo ad implementare una funzione un po’ particolare, in quanto accederemo<br />
all’applicazione nativa “Contatti” e ricaveremo le informazioni di un contatto.<br />
Impareremo ad utilizzare il framework (una sorta di libreria, che ci fornisce delle funzionalità<br />
già pronte) “AddressBook” e come sfruttare le funzioni che ci mette a disposizione.<br />
DEFINIAMO IL PROGETTO<br />
Iniziamo creando un progetto del tipo “View-Based Application” e chiamiamolo “AccessContact”.<br />
Questa volta procederemo come nel primo tutorial, ovvero andremo a definire prima i<br />
componenti via codice, poi li collegheremo tramite Interface Builder.<br />
Apriamo il file “AccessContactViewController.h”, che è la classe della vista che ci viene fornita<br />
con questo template. Inseriamo il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
#import <br />
#import <br />
#import <br />
@interface AccessContactViewController : UIViewController {<br />
! IBOutlet UILabel *labelNome;<br />
! IBOutlet UILabel *labelCognome;<br />
! IBOutlet UILabel *labelTel;<br />
}<br />
- (IBAction)getContatto;<br />
@end<br />
Ormai siete es<strong>per</strong>ti, e avrete subito capito che abbiamo definito tre label e un’azione. Alle righe<br />
2 e 3, <strong>per</strong>ò, abbiamo importato due librerie, che si riferiscono ad “AddressBook”, ovvero all’applicazione<br />
“Contatti”. Questo, <strong>per</strong>ò, non basta <strong>per</strong> poter utilizzare tutte le sue funzioni. Dobbiamo<br />
importare all’interno del nostro progetto anche il framework necessario.<br />
Espandete la sezione “Targets” nel progetto, e cliccate con il tasto destro su “AccessContact”,<br />
selezionando poi “<strong>Get</strong> Info”. Si aprirà una nuova schermata, in cui dobbiamo andare nella sezione<br />
“General”. Nell’angolo in basso a sinistra noteremo un bottone “+”, clicchiamo e si aprirà<br />
un elenco di tutti i framework disponibili:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 48
Selezioniamo “AddressBook.framework” e “AddressBookUI.framework” e clicchiamo poi su<br />
“Add”. Avremo così aggiunto questi due framework al nostro progetto. Possiamo così chiudere<br />
la schermata delle proprietà.<br />
Salviamo il file “AccessContactViewController.h” e facciamo doppio clic su<br />
“AccessContactViewControlle.xib” <strong>per</strong> aprire Interface Builder.<br />
DEFINIAMO LA STRUTTURA GRAFICA<br />
Dobbiamo ora definire l’aspetto grafico della nostra applicazione. Inseriamo le label necessarie<br />
e un bottone, <strong>per</strong> ricreare un aspetto grafico come questo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 49
Le label con il testo “---” sono quelle che poi conterranno le informazioni sul contatto selezionato<br />
dall’utente. Dobbiamo ora collegare gli elementi definiti in precedenza con quelli che abbiamo<br />
appena inserito nella vista.<br />
Tramite il pannello dei documenti selezioniamo “File’s Owner”, e apriamo il “Connections Inspector”.<br />
Potremo vedere i componenti che abbiamo dichiarato:<br />
Ora dobbiamo collegarli nella maniera corretta, ovviamente in base al nome con cui li abbiamo<br />
chiamati: “labelNome”, quindi, andrà collegata con la label a fianco di “Nome” e così via.<br />
L’azione “getContatto”, invece, sarà da collegare al bottone, scegliendo come sempre “Touch<br />
Up Inside” tra le azioni disponibili. Ecco il risultato finale dei collegamenti:<br />
Possiamo salvare tutto e chiudere Interface Builder.<br />
SCRIVIAMO IL CODICE NECESSARIO<br />
Dobbiamo ora implementare i metodi necessari <strong>per</strong> far funzionare l’applicazione. Iniziamo con<br />
la definizione del metodo “getContatto”, ovvero l’azione collegata alla pressione del bottone.<br />
Apriamo il file “AccessContactViewController.m” e inseriamo il seguente codice:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 50
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
-(IBAction)getContatto {<br />
! //Crea l’oggetto necessario<br />
! ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController<br />
alloc] init];<br />
! //Il delegato dell’oggetto è definito nella classe stessa<br />
! picker.peoplePickerDelegate = self;<br />
! //Visualizza l’app Contatti<br />
! [self presentModalViewController:picker animated:YES];<br />
! //Rilascia l’oggetto<br />
! [picker release];<br />
}<br />
Come si può leggere dai commenti, questo metodo istanzia un oggetto chiamato “picker”, che<br />
ci <strong>per</strong>metterà di aprire l’applicazione nativa “Contatti”. Alla riga 5 definiamo il delegato di tale<br />
oggetto: impostando “self”, comunichiamo che sarà la stessa classe (ovvero “AccessCon-<br />
tactViewController”) a definire gli altri metodi necessari, che definiremo tra poco. Alla riga 7,<br />
infine, inseriamo tale oggetto come vista principale della nostra applicazione: l’utente vedrà<br />
così comparire l’applicazione nativa “Contatti” all’interno della nostra applicazione “AccessContact”.<br />
Dobbiamo ora implementare i metodi richiesti dal delegato. Ecco il codice da inserire:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigation-<br />
Controller *)peoplePicker<br />
shouldContinueAfterSelectingPerson:(ABRecordRef)<strong>per</strong>son {<br />
! //Settiamo il nome<br />
labelNome.text = (NSString *)ABRecordCopyValue(<strong>per</strong>son, kABPersonFirstNamePro<strong>per</strong>ty);<br />
! //Settiamo il cognome<br />
labelCognome.text = (NSString *)ABRecordCopyValue(<strong>per</strong>son,<br />
kABPersonLastNamePro<strong>per</strong>ty);!<br />
! //Settiamo il numero di telefono<br />
! ABMultiValueRef multi = ABRecordCopyValue(<strong>per</strong>son, kABPersonPhone-<br />
Pro<strong>per</strong>ty);<br />
! labelTel.text = (NSString*)ABMultiValueCopyValueAtIndex(multi,<br />
0);<br />
! //Rimuove il controller "Contatti"<br />
[self dismissModalViewControllerAnimated:YES];!<br />
return NO;<br />
}<br />
-<br />
(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavig<br />
ationController *)peoplePicker {<br />
// facciamo tornare il controller alla vista principale<br />
! [self dismissModalViewControllerAnimated:YES];<br />
}<br />
Il primo metodo legge le informazioni del contatto selezionato, e le setta nelle apposite label.<br />
L’unico inconveniente è dato dalle righe 7 e 8, che si occupano della lettura del numero di tele-<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 51
fono: viene letto il primo numero presente (in quanto potrebbero anche esserci più numeri). E<br />
se non vi fosse nessun numero associato al contatto? In tal caso l’applicazione crasha. Questo<br />
avviene <strong>per</strong>ché non abbiamo effettuato nessun controllo, ma potete semplicemente risolvere<br />
questo problema tramite un opportuno ciclo if.<br />
Il metodo che inizia alla riga 15, infine, si occupa di chiudere l’applicazione “Contatti” quando<br />
l’utente sceglie di uscire senza selezionare nessun contatto (ovvero quando clicca su “Cancel”).<br />
Potete notare che l’istruzione di tale metodo è uguale a quella presente alla riga 10, che è uguale<br />
a sua volta a quella presente alla riga 7 del primo metodo implementato.<br />
Cliccate su “Build and Go!” e testate la vostra applicazione!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 52
Capitolo 8: Creiamo un mini browser con le UIWebView<br />
Una delle caratteristiche principali dell’<strong>iPhone</strong> è la sua connettività, sia essa tramite WiFi, 3G o<br />
EDGE. Internet, quindi, ricopre un ruolo fondamentale nell’utilizzo di questo dispositivo. Ecco<br />
che sorge spesso necessario implementare una sorta di browser nelle nostre applicazioni, <strong>per</strong><br />
poter visualizzare delle pagine web. Anche in questo l’<strong>SDK</strong> si rivela molto potente, in quanto ci<br />
mette a disposizione un componente praticamente già pronto: le UIWebView. Questo componente<br />
è una sorta di “Safari lite”, in quanto ci <strong>per</strong>mette di visualizzare pagine web tramite lo<br />
stesso motore che è alla base di Safari.<br />
Nel tutorial vedremo come utilizzare le UIWebView, <strong>per</strong> realizzare un nostro mini-browser,<br />
con tre semplici pulsanti: avanti, indietro e ricarica. Certo, non potremo competere con Safari,<br />
ma potrebbe tornarvi molto utile nei vostri programmi.<br />
CREIAMO LA STRUTTURA GRAFICA<br />
Iniziamo creando un nuovo progetto di tipo “View-Based Application” e chiamiamolo “My-<br />
Browser”. Prima di definire l’aspetto della nostra applicazione, dichiariamo un componente che<br />
ci servirà (sarà il componente principale che caricherà le pagine web).<br />
Apriamo il file “MyBrowserViewController.h” e inseriamo la seguente definizione:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
@interface MyBrowserViewController : UIViewController {<br />
IBOutlet UIWebView *webView;<br />
}<br />
@end<br />
Salviamo il file e apriamo “MyBrowserViewController.xib” <strong>per</strong> avviare Interface Builder.<br />
Il template che abbiamo utilizzato ci fornisce già una vista di base, noi iniziamo inserendo nella<br />
parte bassa della vista un componente di tipo UIToolbar e tre bottoni (UIBarButtonItem,<br />
quelli utilizzati nel capitolo 5), separando gli ultimi due tramite un “Flexible Space” (anche questo<br />
già visto). I primi due bottoni ci serviranno <strong>per</strong> muoverci tra le pagine visitate (i classici<br />
“Avanti” e “Indietro”), mentre il terzo servirà a ricaricare la pagina. Ecco come appare la barra<br />
appena definita:<br />
Ora dobbiamo inserire la WebView. Dalla libreria scegliamo un componente “UIWebView” e<br />
inseriamolo nella nostra finestra. Ecco il risultato finale:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 53
DEFINIAMO I COMPONENTI E COLLEGHIAMO LE AZIONI<br />
Abbiamo già concluso con la definizione dell’interfaccia grafica. Dobbiamo ora definire i componenti<br />
che ci serviranno e collegare le relative azioni. Vedrete che si rivelerà tutto molto semplice,<br />
in quanto troveremo già tutto pronto.<br />
Iniziamo cliccando sul “File’s Owner” (che troviamo nel Pannello dei documenti). Colleghiamo<br />
il componente “webView” (che è quello definito all’inizio del tutorial) con la UIWebView che<br />
abbiamo appena inserito nella nostra applicazione. Se abbiamo eseguito questo passaggio correttamente<br />
avremo un pannello “Connections Inspector” come questo:<br />
Dopo aver fatto questo semplice collegamento, andiamo ancora nel Pannello dei documenti ed<br />
espandiamo il componente View e selezioniamo la UIWebView :<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 54
Andiamo nel “Connections Inspector” e noteremo che ci sono già delle azioni definite (“go-<br />
Back”, “goForward”, etc.), non dovremo far altro che collegarle con i bottoni adeguati. Ecco le<br />
associazioni da fare:<br />
• “goBack” con il bottone “”, ovvero <strong>per</strong> andare alla pagina successiva (della cronologia);<br />
• “reload” con il bottone “Ricarica”, <strong>per</strong> ricaricare la pagina web.<br />
Se avete eseguito tutto correttamente avrete un risultato come questo:<br />
Tutto molto semplice e veloce!<br />
Salviamo tutto e chiudiamo Interface Builder.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 55
SCRIVIAMO IL CODICE PER APRIRE LA PAGINA DESIDERATA<br />
Dobbiamo ora inserire il codice che si occupa di caricare la pagina web desiderata e mostrarla<br />
nella UIWebView. Utilizziamo un metodo che viene caricato all’avvio dell’applicazione, e che ci<br />
<strong>per</strong>mette di settare i comportamenti iniziali del nostro browser.<br />
Aprite il file “MyBrowserViewController.m” e inserite il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
- (void)viewDidLoad{<br />
! //indirizzo web da caricare<br />
! NSString *indirizzo = @"http://www.bubidevs.net";<br />
! //crea un oggetto URL<br />
! NSURL *url = [NSURL URLWithString:indirizzo];<br />
! NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];<br />
! // visualizza la pagina nella UIWebView<br />
! [webView loadRequest:requestObj];<br />
}<br />
Come potete vedere si tratta solo di quattro istruzioni!<br />
Definiamo, alla riga 3, l’indirizzo che vogliamo aprire, mentre alle righe 5 e 6 inizializiamo i<br />
componenti necessari <strong>per</strong> poter visualizzare la pagina (non preoccupatevi troppo, sono sempre<br />
questi da utilizzare). All’istruzione 8, infine, settiamo i componenti che abbiamo appena creato<br />
nella UIWebView, in modo che venga mostrata la pagina web all’utente.<br />
E se volessimo caricare dei file HTML che abbiamo in locale? Semplice, modificate così le<br />
istruzioni alle righe 3 e 5:<br />
2<br />
3<br />
4<br />
5<br />
! //indirizzo web da caricare!<br />
! NSString *indirizzo = [[NSBundle mainBundle]<br />
pathForResource:@"index" ofType:@"html"];<br />
! //crea un oggetto URL<br />
! NSURL *url = [NSURL fileURLWithPath:indirizzo];<br />
in questo modo caricherà il file "index.html" che si deve trovare, <strong>per</strong>ò, nella stessa cartella in<br />
cui viene seguita l’applicazione (quindi dovete prima importarla nel vostro progetto). Semplice<br />
vero?<br />
Cliccate su “Build and Go!” e provate il vostro <strong>per</strong>sonalissimo browser!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 56
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 57
Capitolo 9: UITableView, gestiamo le tabelle<br />
Fino ad ora abbiamo analizzato dei componenti base, molto semplici sia da impostare che da<br />
utilizzare. Il componente più utilizzato, <strong>per</strong>ò, è sicuramente quello che gestisce le tabelle, ovvero<br />
la UITableView. In moltissime applicazioni, infatti, esse vengono utilizzate <strong>per</strong> mostrare<br />
delle informazioni all’utente, che può anche interagire con questi dati.<br />
In questo capitolo vedremo come definire una tabella, come inserire al suo interno dei valori e<br />
come definire dei comportamenti (ad esempio la cancellazione delle righe), necessari <strong>per</strong> renderla<br />
utilizzabile dall’utente.<br />
Questo capitolo è suddiviso in tre parti:<br />
1.Creazione e definizione de"a tabe"a;<br />
2.Inserimento di alcune funzionalità;<br />
3.Implementazione de"a ricerca.<br />
Analizzeremo queste parti una alla volta, passo <strong>per</strong> passo, in modo da comprendere bene ogni<br />
singola cosa che andremo a realizzare.<br />
PARTE 1: CREIAMO E DEFINIAMO LA TABELLA<br />
La prima parte di questo tutorial è dedicata alla creazione della struttura dell’applicazione: ne<br />
definiremo la grafica, la lista degli elementi da visualizzare e come mostrarli all’interno delle<br />
celle. Il tutto sarà fatto con la solita semplicità, sfruttando tutte le caratteristiche che XCode e<br />
l’<strong>SDK</strong> ci mettono a disposizione, semplificando il nostro lavoro.<br />
CREIAMO UN NUOVO PROGETTO<br />
Aprimo Xcode, selezioniamo “File -> New Project”. Nel menù che ci appare selezioniamo “Navigation-based<br />
Application”, clicchiamo su “Choose…” e immettiamo come nome “tableView<strong>Tutorial</strong>”<br />
e fate clic su “Save”. Abbiamo così creato il nostro nuovo progetto.<br />
Questo template di XCode ci fornisce già una tabella con una barra di navigazione, semplificandoci<br />
notevolmente il lavoro!<br />
Nota: questo tutorial funziona con <strong>SDK</strong> 3.0 e su<strong>per</strong>iori.<br />
Aprendo il file "RootViewController.xib" con Interface Builder possiamo notare la struttura già<br />
pronta, non dovremo toccare niente!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 58
INSERIAMO IL CODICE NECESSARIO<br />
A differenza di tutti i passaggi che dovevano essere eseguiti fino al <strong>SDK</strong> 2.x, dovremo solamente<br />
inserire poche righe di codice <strong>per</strong> avere la nostra tabella già pronta e funzionante!<br />
Apriamo il file "RootViewController.h" e inseriamo la dichiarazione del seguente componente:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
@interface RootViewController : UITableViewController {<br />
! NSMutableArray *lista;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSMutableArray *lista;<br />
@end<br />
Abbiamo definito un array in cui inseriamo tutti gli elementi che devono poi essere visualizzati<br />
nella tabella. Notate che abbiamo utilizzato un NSMutableArray, questo <strong>per</strong>ché dovremo avere<br />
la possibilità di poter modificare gli elementi che lo compongono (analizzeremo meglio questo<br />
aspetto quando sarà necessario).<br />
Spostiamoci ora nel file “RootViewController.m” e iniziamo inserendo queste istruzioni:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 59
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
#import "RootViewController.h"<br />
@implementation RootViewController<br />
@synthesize lista;<br />
- (void)viewDidLoad {<br />
[su<strong>per</strong> viewDidLoad];<br />
!<br />
! self.title = @"Prodotti Apple";<br />
!<br />
! //elementi da visualizzare nella tabella<br />
! ! lista = [[NSMutableArray alloc] initWithObjects: @"<strong>iPhone</strong>",<br />
@"iPod",@"iPod Touch", @"iMac", @"iBook", @"MacBook", @"MacBook<br />
Pro", @"Mac Pro", @"PowerBook", nil];!<br />
// Uncomment the following line to display an Edit button in the<br />
navigation bar for this view controller.<br />
// self.navigationItem.rightBarButtonItem = self.editButtonItem;<br />
}<br />
Analizziamo quello che abbiamo appena scritto. Chi ha già un pochino di es<strong>per</strong>ienza con la<br />
programmazione <strong>per</strong> <strong>iPhone</strong> conoscerà certamente il metodo “viewDidLoad“: questo viene<br />
eseguito subito dopo il caricamento della vista, e ci <strong>per</strong>mette di settare tutte le variabili e tutti i<br />
parametri all’avvio. Per prima cosa abbiamo impostato il titolo alla nostra tabella, che apparirà<br />
nella NavigationBar presente nella vista (riga 10). Subito dopo viene inizializzata la lista (che è<br />
un oggetto NSMutableArray), inserendoci alcuni elementi (riga 13).<br />
Per ora non fate caso alle righe 15 e 16, ci saranno utili nella seconda parte del tutorial.<br />
Ora dobbiamo definire i metodi che si occupano di popolare la tabella. Scorrendo il file<br />
“RootViewController.m” li troverete già (XCode li inserisce sempre di default), dovete solo<br />
completarli. Iniziamo definendo i seguenti due:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {<br />
return 1;<br />
}<br />
// Setta il numero di righe della tabella .<br />
- (NSInteger)tableView:(UITableView *)tableView<br />
numberOfRowsInSection:(NSInteger)section {<br />
return [lista count];<br />
}<br />
Il primo metodo che incontriamo è “numberOfSectionsInTableView“. Se provate a modificare<br />
questo valore, vedrete che (quando eseguirete l’applicazione) la lista degli oggetti sarà ripetuta<br />
più volte. Provare <strong>per</strong> credere! A cosa serve? Nel caso in cui vogliate creare una tabella suddivi-<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 60
sa in più sezioni, ad esempio come quella dell’applicazione nativa “Contatti”, che suddivide gli<br />
elementi in ordine alfabetico.<br />
Il secondo è “numberOfRowInSection“, e setta il numero di celle in ogni sezione (nel nostro<br />
esempio avremo una sola sezione). Questo valore deve corrispondere al numero di elementi che<br />
vogliamo inserire nella tabella, quindi quelli contenuti nell’oggetto “lista”.<br />
Ci resta solamente da inserire un metodo, quello che si occupa di inserire gli elementi nelle celle<br />
della tabella. Ecco il metodo in questione:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
// Setta il contenuto delle varie celle<br />
- (UITableViewCell *)tableView:(UITableView *)tableView<br />
cellForRowAtIndexPath:(NSIndexPath *)indexPath{<br />
!<br />
! UITableViewCell *cell = [tableView<br />
dequeueReusableCellWithIdentifier:@"cellID"];<br />
!<br />
! if (cell == nil){<br />
! ! cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero<br />
reuseIdentifier:@"cellID"] autorelease];<br />
! ! //setta lo stile con cui vengono selezionate le righe<br />
! ! cell.selectionStyle = UITableViewCellSelectionStyleNone;!<br />
! }<br />
! //inseriamo nella cella l'elemento della lista corrispondente<br />
! cell.textLabel.text = [lista objectAtIndex:indexPath.row];<br />
! return cell;<br />
}<br />
Questo è il metodo (fondamentale ed obbligatorio) che si occupa di settare in maniera corretta<br />
le celle della tabella. Alla riga 4 troviamo la dichiarazione di una cella, che viene poi allocata alla<br />
riga 7. Con l’istruzione presente alla riga 9 definiamo come deve essere l’aspetto delle righe<br />
quando vengono selezionate dall’utente. Con questa istruzione l’utente non potrà selezionare<br />
nessuna riga, se invece la togliamo avremo la classica selezione con sfondo blu.<br />
Alla riga 13, infine, settiamo il valore contenuto nella cella: esso deve essere letto dall’array, nella<br />
posizione uguale a quella della riga (ricordatevi che sia la numerazione dell’array che delle celle<br />
parte da zero).<br />
Cliccate ora su “Build and Go!”: la nostra tabella inizia a prendere forma!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 61
PARTE 2: INSERIAMO ALCUNE FUNZIONALITÀ<br />
Abbiamo visto come definire una tabella. In questa seconda parte vedremo come aggiungere<br />
due funzionalità davvero molto importanti: la cancellazione delle singole celle e la possibilità di<br />
renderle selezionabili. Vedrete che <strong>per</strong> entrambe le caratteristiche dovremo inserire davvero<br />
poco codice, in quanto è già tutto definito.<br />
PERMETTIAMO LA CANCELLAZIONE DI UNA RIGA<br />
La prima cosa da fare è inserire il bottone che <strong>per</strong>mette di accedere alla modifica della tabella.<br />
Per fare ciò ci basta decommentare una riga che dovreste già trovare nel metodo viewDidLoad:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
15<br />
16<br />
17<br />
#import "RootViewController.h"<br />
@implementation RootViewController<br />
@synthesize lista;<br />
- (void)viewDidLoad{<br />
[su<strong>per</strong> viewDidLoad];<br />
! // codice aggiunto nella prima parte del tutorial<br />
...<br />
// Uncomment the following line to display an Edit button in the<br />
navigation bar for this view controller.<br />
self.navigationItem.rightBarButtonItem = self.editButtonItem;<br />
}<br />
Tutto molto semplice e veloce grazie alle API di Apple.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 62
Se provate ad eseguire l'applicazione noterete che cancellando una riga essa non viene rimossa<br />
dalla tabella. Questo avviene <strong>per</strong>ché non abbiamo ancora concluso di implementare questa<br />
funzionalità. Inseriamo, quindi, il seguente metodo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
// Elimina l'elemento dalla tabella e dalla lista<br />
- (void)tableView:(UITableView *)tableView<br />
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle<br />
forRowAtIndexPath:(NSIndexPath *)indexPath {<br />
!<br />
! //controlla se l'azione compiuta è un'eliminazione<br />
! if (editingStyle == UITableViewCellEditingStyleDelete) {<br />
! ! //elimina l'elemento dalla lista<br />
! ! [lista removeObjectAtIndex:indexPath.row];<br />
! ! //elimina le'elemento dalla tabella<br />
! ! [self.tableView deleteRowsAtIndexPaths:[NSArray<br />
arrayWithObject:indexPath]<br />
withRowAnimation:UITableViewRowAnimationFade];<br />
! !<br />
! }<br />
}<br />
Come possiamo notare dalla struttura un po’ complicata, questo è un metodo del protocollo<br />
UITableView, proprio come quello che abbiamo implementato nella prima parte.<br />
Il costrutto if (riga 5) esegue un controllo che, come spiega il commento, controlla se l’azione<br />
eseguita sulla tabella è di cancellazione di una riga. Direte voi: “Cosa posso fare d’altro?” Per<br />
ora niente, <strong>per</strong>ché la nostra tabella supporta solo l’eliminazione di una riga, ma volendo si potrebbe<br />
implementare anche l’inserimento di una nuova riga, oppure altre azioni. È sempre questo<br />
metodo che si occupa di gestire tutte le azioni sulla tabella. Ecco spiegata la necessità di<br />
questo controllo. Tornando al codice, all’interno dell’if possiamo notare due istruzioni, che<br />
eliminano l’elemento sia dalla lista (riga 7) che dalla tabella (riga 9). In questo modo la cancellazione<br />
di una riga è davvero implementata.<br />
RENDIAMO LE CELLE SELEZIONABILI<br />
Vediamo ora di implementare un’altra funzione. Vogliamo che quando l’utente seleziona una<br />
cella appaia un pop-up che contenga il nome dell’elemento selezionato. Ovviamente questa<br />
azione non ha una grande utilità, ma vi <strong>per</strong>metterà di imparare come gestire le selezioni dell’utente<br />
e vedrete, inoltre, come creare un pop-up.<br />
Prima di implementare il metodo necessario, eliminate dal metodo<br />
tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath;<br />
la seguente istruzione (vi ho spiegato nella prima parte a cosa serviva):<br />
1 cell.selectionStyle = UITableViewCellSelectionStyleNone;<br />
altrimenti le celle non saranno selezionabili.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 63
Nel solito file “RootViewController.m” inserite ora questo metodo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
// Se selezioniamo una riga appare un pop-up con l'elemento in questione<br />
- (void)tableView:(UITableView *)tableView<br />
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {<br />
! UIAlertView *popUp = [[UIAlertView alloc] initWithTitle:@"Hai selezionato:"<br />
message:[lista objectAtIndex:indexPath.row]<br />
delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];<br />
! [popUp show];<br />
! [popUp release];<br />
}<br />
Questo è il metodo che si occupa di eseguire una certa azione quando l’utente seleziona una<br />
cella. Alla riga 3 possiamo notare la definizione del pop-up, che conterrà un messaggio con il<br />
nome della cella selezionata. È possibile creare pop-up con diversi bottoni o più messaggi, vi<br />
basterà guardare la documentazione <strong>per</strong> trovare tutte le varianti possibili.<br />
Alla riga 4, infine, viene mostrato il pop-up appena definito.<br />
Cliccate ora su “Build and Go!” e testate la nuova tabella!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 64
PARTE 3: IMPLEMENTIAMO LA RICERCA<br />
Nella terza e ultima parte di questo lungo tutorial dedicato alle tabelle, vedremo come aggiungere<br />
un box di ricerca. Il comportamento sarà del tutto simile a quello della ricerca presente<br />
nell’applicazione nativa “Contatti”.<br />
Vedrete che questa o<strong>per</strong>azione si rivelerà molto semplice, infatti Apple ha davvero migliorato<br />
questo aspetto con le ultime versioni del <strong>SDK</strong>.<br />
AGGIUNGIAMO IL BOX DI RICERCA<br />
Facciamo doppio clic sul file “RootViewController.xib” <strong>per</strong> aprire IB, in cui dovremo inserire la<br />
nostra barra di ricerca. Dalla Libreria selezioniamo un componente “Search Bar and Search Display<br />
Controller”, e trasciniamolo sopra l’elemento “Table View” che vedete nel Pannello dei<br />
documenti.<br />
Se avete eseguito tutto correttamente la vostra tabella mostrerà ora anche una barra di ricerca:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 65
Ancora una volta davvero tutto molto semplice! Salvate tutto e chiudere pure Interface Buider.<br />
MODIFICHIAMO I METODI GIÀ ESISTENTI<br />
Prima di implementare la ricerca vera e propria, dobbiamo fare delle piccole modifiche ai metodi<br />
già presenti nel nostro progetto.<br />
Iniziamo aprendo il file “RootViewController.h” e completiamo così la definizione della classe:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
@interface RootViewController : UITableViewController {<br />
! NSMutableArray *lista;<br />
! NSMutableArray *filteredListContent;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSMutableArray *lista;<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSMutableArray *filteredListContent;<br />
@end<br />
Abbiamo semplicemente dichiarato una nuova lista (riga 3), che conterrà gli elementi “filtrati”,<br />
ovvero quelli che corrispondono al criterio di ricerca.<br />
Ora dobbiamo modificare i metodi che si occupano dell’inizializzazione della tabella. Iniziamo<br />
dal metodo “viewDidLoad” e dalla funzione “@synthetize”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 66
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
#import "RootViewController.h"<br />
@implementation RootViewController<br />
@synthesize lista, filteredListContent;<br />
- (void)viewDidLoad {<br />
[su<strong>per</strong> viewDidLoad];<br />
!<br />
! self.title = @"Prodotti Apple";<br />
!<br />
! //elementi da visualizzare nella tabella<br />
! lista = [[NSMutableArray alloc] initWithObjects:@"<strong>iPhone</strong>", @"i-<br />
Pod", @"iPod Touch", @"iMac", @"iBook", @"MacBook", @"MacBook Pro",<br />
@"Mac Pro", @"PowerBook", nil];<br />
! ! !<br />
// Uncomment the following line to display an Edit button in the<br />
navigation bar for this view controller.<br />
self.navigationItem.rightBarButtonItem = self.editButtonItem;<br />
!<br />
! // crea la lista filtrata, inizializzandola con il numero di<br />
elementi dell'array "lista"<br />
! filteredListContent = [[NSMutableArray alloc] initWithCapacity:<br />
[lista count]];<br />
! //inserisce in questa nuova lista gli elementi della lista originale<br />
! [filteredListContent addObjectsFromArray: lista];<br />
}<br />
Potete notare che la prima parte del metodo “viewDidLoad” è uguale a quella che già abbiamo<br />
scritto nei precedenti tutorial. Alle righe 19 e 21, invece, abbiamo inserito due istruzioni, che<br />
hanno il compito di inizializzare il nuovo array, che ci servirà nell’algoritmo di ricerca. Inizialmente<br />
questa lista coinciderà con quella degli elementi iniziali, mentre poi verrà modificata<br />
mentre l’utente inserisce la stringa di ricerca.<br />
Il secondo metodo da modificare è “numberOfRowsInSection”. Ecco il nuovo codice:<br />
1<br />
2<br />
3<br />
4<br />
- (NSInteger)tableView:(UITableView *)tableView<br />
numberOfRowsInSection:(NSInteger)section{<br />
! //il numero di righe deve corrispondere al numero di elementi<br />
della lista<br />
! return [filteredListContent count];<br />
}<br />
Questa modifica va eseguita in quanto la tabella ora non è più composta dagli elementi della<br />
lista originale, ma da quelli della lista filtrata, ovvero di quegli elementi selezionati mediante la<br />
ricerca. Ovviamente se l’utente non esegue nessuna ricerca, gli elementi della lista filtrata corrisponderanno<br />
agli elementi della lista originale.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 67
Se vi è chiaro questo ragionamento, è facile intuire quali saranno i prossimi metodi da modificare:<br />
il primo è “cellForRowAtIndexPath:”, ovvero il metodo che si occupa di inserire i valori<br />
nelle celle. Modificate l’ultima istruzione al suo interno nella seguente maniera:<br />
1<br />
2<br />
/inseriamo nella cella l'elemento della lista corrispondente<br />
! cell.textLabel.text = [filteredListContent<br />
objectAtIndex:indexPath.row];<br />
Modifichiamo, poi, il metodo “commitEditingStyle”, aggiungendo l’istruzione alla riga 8:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
- (void)tableView:(UITableView *)tableView<br />
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle<br />
forRowAtIndexPath:(NSIndexPath *)indexPath {<br />
!<br />
! //controlla se l'azione compiuta è un'eliminazione<br />
! if (editingStyle == UITableViewCellEditingStyleDelete) {<br />
! ! NSLog(@"cancellato");<br />
! ! //elimina l'elemento dalle due liste<br />
! ! [lista removeObjectAtIndex:indexPath.row];<br />
! ! [filteredListContent removeObjectAtIndex:indexPath.row];<br />
! ! //elimina le'elemento dalla tabella<br />
! ! [self.tableView deleteRowsAtIndexPaths:[NSArray<br />
arrayWithObject:indexPath]<br />
withRowAnimation:UITableViewRowAnimationFade];<br />
! !<br />
! }<br />
}<br />
L’ultimo metodo da modificare, infine, è “didSelectRowAtIndexPath:” e anche in questo caso<br />
l’unica modifica riguarda proprio la lista di riferimento.<br />
1<br />
2<br />
3<br />
4<br />
5<br />
- (void)tableView:(UITableView *)tableView<br />
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {<br />
! UIAlertView *popUp = [[UIAlertView alloc] initWithTitle:@"Hai<br />
selezionato:" message:[filteredListContent<br />
objectAtIndex:indexPath.row] delegate:self cancelButtonTitle:@"OK"<br />
otherButtonTitles:nil];<br />
! [popUp show];<br />
! [popUp release];<br />
}<br />
Abbiamo così eseguito tutte le modifiche necessarie!<br />
IMPLEMENTIAMO LA RICERCA<br />
È arrivato il momento di implementare la ricerca vera e propria. Prima di mostrarvi i passaggi<br />
necessari, devo premettere che il codice non è stato scritto da me, ma l’ho preso da un esempio<br />
realizzato dalla stessa Apple. I commenti, quindi, saranno davvero pochi, anche <strong>per</strong>ché non è<br />
fondamentale capire come funziona tale algoritmo, in quanto lo stesso codice si può utilizzare<br />
in qualsiasi altra applicazione che necessiti di una ricerca.<br />
Iniziate inserendo questi due metodi:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 68
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller<br />
shouldReloadTableForSearchString:(NSString *)searchString{<br />
[self filterContentForSearchText:searchString scope:<br />
! [[self.searchDisplayController.searchBar scopeButtonTitles]<br />
objectAtIndex:[self.searchDisplayController.searchBar selectedScope-<br />
ButtonIndex]]];<br />
// Return YES to cause the search result table view to be reloaded.<br />
return YES;<br />
}<br />
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller<br />
shouldReloadTableForSearchScope:(NSInteger)searchOption{<br />
!<br />
[self<br />
filterContentForSearchText:[self.searchDisplayController.searchBar<br />
text] scope:<br />
! [[self.searchDisplayController.searchBar scopeButtonTitles]<br />
objectAtIndex:searchOption]];<br />
// Return YES to cause the search result table view to be reloaded.<br />
return YES;<br />
}<br />
I due metodi appena mostrati fanno parte del delegato “UISearchDisplayController”, che si<br />
occupa di gestire in maniera corretta la barra di ricerca.<br />
Ora dobbiamo inserire l’algoritmo di ricerca vero e proprio. Eccovelo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
- (void)filterContentForSearchText:(NSString*)searchText<br />
scope:(NSString*)scope{<br />
!<br />
! // <strong>per</strong> prima cosa azzeriamo l'array della ricerca<br />
! [self.filteredListContent removeAllObjects];<br />
!<br />
! // controlliamo se gli elementi della tabella corrispondono alla<br />
ricerca<br />
! NSString *cellTitle;<br />
! for (cellTitle in lista){<br />
! ! NSComparisonResult result = [cellTitle compare:searchText<br />
options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText<br />
length])];<br />
! ! if (result == NSOrderedSame){<br />
! ! ! [filteredListContent addObject:cellTitle];<br />
! ! }<br />
! }<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 69
Per questo algoritmo non voglio spendere parole, in quanto, come detto in precedenza, è stato<br />
scritto da Apple, quindi non posso <strong>per</strong>mettermi di fare modifiche!<br />
Cliccate ora su “Build and Go!”, se avete eseguito tutto correttamente si aprirà la vostra applicazione<br />
con la barra di ricerca <strong>per</strong>fettamente funzionante!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 70
Capitolo 10: gestiamo più viste (file “.xib” multipli)<br />
In questo capitolo vedremo un’aspetto fondamentale nella creazione di un’applicazione, ovvero<br />
la gestione di più viste. In tutte le applicazioni, infatti, sono presenti diverse viste (“finestre”,<br />
<strong>per</strong> usare un termine più generico), che vengono spesso create con Interface Builder (e quindi<br />
diversi file “.xib”) data la sua comodità.<br />
L’applicazione che andremo a realizzare sarà davvero molto semplice, infatti consisterà in due<br />
semplici viste, che potremo scambiare semplicemente cliccando su un bottone. È importante<br />
seguire bene tutti i passaggi, in modo che possiate replicare la stessa struttura anche nelle vostre<br />
applicazioni più complesse, senza errori e senza <strong>per</strong>dere tempo prezioso.<br />
CREIAMO UN NUOVO PROGETTO<br />
Iniziamo il nostro tutorial creando un nuovo progetto di tipo “View-based application” e chiamiamolo<br />
“view<strong>Tutorial</strong>”<br />
Il template di XCode ci mette già a disposizione una vista, che sarà quella di partenza (quella<br />
che viene caricata all’avvio dell’applicazione, chiamata in questo caso “view<strong>Tutorial</strong>ViewController”).<br />
Creiamo, <strong>per</strong> prima cosa, la seconda vista necessaria <strong>per</strong> questa mini-applicazione.<br />
Facciamo clic con il tasto destro sul nome del nostro progetto e selezioniamo “Add -> New File…”.<br />
Scegliamo, poi, un template “UIViewController” e spuntiamo la voce “With XIB for user<br />
interface”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 71
Inseriamo come nome “VistaDue” e clicchiamo su “Finish”. Abbiamo così creato una nuova vista<br />
con la relativa classe che la gestisce, niente di più semplice!<br />
DEFINIAMO LA PRIMA VISTA<br />
Apriamo il file “view<strong>Tutorial</strong>ViewController.h” e inseriamo le seguenti dichiarazioni:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
#import <br />
@class VistaDue;<br />
@interface view<strong>Tutorial</strong>ViewController : UIViewController {<br />
! IBOutlet VistaDue *vistaDueController;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet VistaDue *vistaDueController;<br />
-(IBAction)cambiaVista;<br />
@end<br />
Alla riga 6 abbiamo definito un elemento di tipo VistaDue, che sarà proprio la vista che caricheremo.<br />
Abbiamo, inoltre, definito anche un’azione “cambiaVista”, che assoceremo ad un pulsante,<br />
sarà l’evento che avvierà il cambio di vista.<br />
Salviamo il file appena modificato e apriamo il file ”view<strong>Tutorial</strong>ViewController.xib”. In Interface<br />
Builder apriamo il Pannello dei documenti e inseriamo un elemento del tipo “UIView-<br />
Controller” al suo interno:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 72
Selezioniamo il componente appena inserito e dal pannello Identity Inspector selezioniamo<br />
come classe “VistaDue”:<br />
Ora inserite nella vista principale (non nel ViewController che abbiamo appena inserito) un<br />
bottone. Ecco come si presenta la mia vista:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 73
Ora selezionate il File’s Owner. Dobbiamo collegare i due componenti che abbiamo definito<br />
poco fa. Colleghiamo l’azione “cambiaVista” con il bottone, selezionando “Touch Up Inside”<br />
quando appare il menù di scelta dell’azione. Collegate, infine, l’elemento “vistaDueController”<br />
con l’UIViewController che abbiamo inserito poco prima. Se avete eseguito tutto correttamente<br />
avrete un pannello che si presenta così:<br />
Possiamo salvare e chiudere questa vista.<br />
DEFINIAMO LA “VISTADUE”<br />
Dobbiamo ora definire la seconda vista. Apriamo <strong>per</strong> prima cosa il file “VistaDue.h” e definite<br />
semplicemente questa azione (riga 7):<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
#import <br />
@interface VistaDue : UIViewController {<br />
}<br />
-(IBAction)tornaIndietro;<br />
@end<br />
Salvate il file e apriamo “VistaDue.xib”. Anche in questo caso inseriamo solamente un bottone<br />
nella vista, che ci <strong>per</strong>metterà di tornare alla prima vista:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 74
Selezioniamo il File’s Owner e colleghiamo l’azione “tornaIndietro” con il bottone che abbiamo<br />
inserito, selezionando sempre “Touch Up Inside” come azione:<br />
Salviamo e chiudiamo pure Interface Builder.<br />
SCRIVIAMO IL CODICE NECESSARIO<br />
Dobbiamo ora scrivere il codice che ci <strong>per</strong>metterà di passare da una vista all’altra. Vedrete che<br />
le istruzioni necessarie saranno davvero poche.<br />
Apriamo il file “view<strong>Tutorial</strong>ViewController.m” e inseriamo il seguente codice:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 75
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
#import "view<strong>Tutorial</strong>ViewController.h"<br />
#import "VistaDue.h"<br />
@implementation view<strong>Tutorial</strong>ViewController<br />
@synthesize vistaDueController;<br />
-(IBAction)cambiaVista{<br />
! vistaDueController = [[VistaDue alloc]<br />
initWithNibName:@"VistaDue" bundle:nil];<br />
! vistaDueController.modalTransitionStyle = UIModalTransition-<br />
StyleFlipHorizontal;<br />
! [self presentModalViewController:self.vistaDueController<br />
animated:YES];<br />
}<br />
Alla riga 9 abbiamo inizializzato la vista, inserendo anche il nome del file .xib che deve essere<br />
caricato. La riga 10, invece, ci <strong>per</strong>mette di impostare l’animazione del passaggio dalla prima alla<br />
seconda vista. Ci sono tre animazioni già predisposte e disponibili:<br />
1. UIModalTransitionStyleCoverVertical, il caricamento della nuova vista sarà verticale, dal basso<br />
verso l’alto;<br />
2. UIModalTransitionStyleFlipHorizontal, c’è la rotazione flip-side, ovvero come se venisse mostrato<br />
il retro della vista;<br />
3. UIModalTransitionStyleCrossDissolve, dissolvenza incrociata.<br />
L’ultima istruzione (riga 11) <strong>per</strong>mette di mostrare la seconda vista, rendendola così visibile all’utente.<br />
Ora non ci resta che definire il metodo “tornaIndietro” della classe VistaDue. Apriamo il file<br />
“VistaDue.m” e inseriamo la definizione di tale metodo:<br />
1<br />
2<br />
3<br />
- (IBAction)tornaIndietro{<br />
! [[self parentViewController]<br />
dismissModalViewControllerAnimated:YES];<br />
}<br />
Questa istruzione ci <strong>per</strong>mette di uscire dalla vista corrente e tornare a quella che era visualizzata<br />
precedentemente (nel nostro caso la vista “view<strong>Tutorial</strong>ViewController”).<br />
Abbiamo concluso! Clicchiamo su “Build and Run” e controlliamo che l’applicazione funzioni<br />
correttamente!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 76
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 77
Capitolo 11: Come creare una TabBar Application<br />
Uno dei componenti più utilizzati (e uno dei più apprezzati dagli utenti finali) sono le TabBar,<br />
che avete già conosciuto nel capitolo 2. In questo tutorial vedremo come creare una struttura<br />
di base, inserendo due viste generiche e una più particolare e utile: una tabella integrata ad una<br />
NavigationBar, che ci <strong>per</strong>metterà di navigare nei sottolivelli della tabella (<strong>per</strong> capirci, la struttura<br />
che è presente nell’applicazione nativa iPod).<br />
PARTE 1: LA STRUTTURA DI BASE<br />
Abbiamo già descritto cosa faremo in questa prima parte: realizzeremo la struttura di base, che<br />
ci <strong>per</strong>metterà di inserire diverse viste nella tab. È importante seguire bene tutti i passaggi <strong>per</strong><br />
non ritrovarsi con errori strani, che spesso portano a <strong>per</strong>dere tempo e possono essere facilmente<br />
evitati.<br />
CREIAMO UNA TABBAR “PULITA”<br />
Iniziamo creando un nuovo progetto di tipo “Tab Bar Application” e chiamandolo “TabBar<strong>Tutorial</strong>”.<br />
Vogliamo andare a definire una struttura di base pulita, <strong>per</strong>sonalizzandola poi a nostro<br />
piacimento. Eliminiamo, quindi, alcuni componenti che XCode ha già creato <strong>per</strong> noi, ma che<br />
non vogliamo sfruttare: cancelliamo il file “SecondView.xib”, “FirstViewController.h” e<br />
“FirstViewController.m”.<br />
Possiamo ora fare doppio clic su “MainWindow.xib”, si aprirà Interface Builder che ci mostrerà<br />
questo layout <strong>per</strong> la nostra applicazione:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 78
Selezioniamo ognuno dei tab ed eliminiamolo, ottenendo questa struttura:<br />
Salviamo questo file e chiudiamo pure Interface Builder.<br />
DEFINIAMO LE DUE VISTE<br />
Dobbiamo ora definire le due viste che dovremo inserire nella nostra applicazione. Dal menù<br />
“File” scegliamo “New File…” e selezioniamo “Empty XIB”. Creiamo due di questi file chiamandoli,<br />
rispettivamente, “PrimaVista” e “SecondaVista”.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 79
Nella cartella “Resources” del nostro progetto vedremo i due file appena creati:<br />
Dobbiamo ora creare anche le due classi che gestiranno le due viste: nel tutorial non serviranno<br />
a niente, ma voglio implementarle in modo da darvi già una struttura che potrete utilizzare nelle<br />
vostre applicazioni.<br />
Andiamo, quindi, in “File -> New File…” e spostiamoci nella sezione “Cocoa Touch Class”, in<br />
cui selezioniamo il modello “UIViewController”: anche in questo caso dobbiamo creare due<br />
classi, chiamate “PrimaVistaController” e “SecondaVistaController”.<br />
Possiamo spostare i file appena creati nella sezione “Classes” del nostro progetto. Abbiamo così<br />
definito tutti i componenti necessari, non ci resta che definire la struttura grafica delle due viste.<br />
CREIAMO L’ASPETTO GRAFICO DELLE DUE VISTE<br />
Clicchiamo su “PrimaVista.xib” <strong>per</strong> aprirla in Interface Builder. Dalla Libreria, inseriamo una<br />
“UIView” all’interno del Pannello dei Documenti (”Tools -> Reveal in Document Window”).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 80
Apriamo la vista appena inserita e modifichiamone l’aspetto a nostro piacimento (io <strong>per</strong> semplicità<br />
inserirò solo due label, in questo tutorial non ci servirà altro). Dall’”Attributes Inspector”<br />
selezioniamo “Tab Bar” dal sotto-menù a tendina “Bottom Bar”:<br />
Questa proprietà non ha nessun fine pratico, <strong>per</strong>ò ci consente di aver una visione completa della<br />
nostra vista, tenendo in considerazione anche la tab bar (in questo modo saprete esattamente<br />
quanto spazio avete a disposizione <strong>per</strong> i vostri componenti). Ecco come si presenta la nostra<br />
vista:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 81
Ora dobbiamo collegare questa vista con la classe che abbiamo definito in precedenza. Sempre<br />
dal Pannello dei Documenti selezioniamo il “File’s Owner”:<br />
In “Identity Inspector” selezioniamo “PrimaVistaController” dal menù a tendina “Class”.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 82
Andiamo poi in “Connections Inspector” e colleghiamo l’elemento “view” con la vista che abbiamo<br />
appena creato. Se abbiamo eseguito il passaggio in maniera corretta avremo questo risultato:<br />
Abbiamo così completato la definizione della vista. Eseguiamo lo stesso procedimento anche<br />
<strong>per</strong> il file “SecondaVista.xib”, collegandola <strong>per</strong>ò alla classe “SecondaVistaController”. Possiamo<br />
poi salvare tutto e chiudere Interface Builder.<br />
IMPOSTIAMO LA TABBAR<br />
Ora è giunto il momento di impostare la struttura vera e propria della nostra Tab Bar. Apriamo<br />
il file “MainWindow.xib”<br />
Dalla Libreria inseriamo due componenti UIViewController trascinandoli nella “Tab Bar” posta<br />
a fondo vista:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 83
Il risultato finale sarà il seguente:<br />
Iniziamo facendo clic sul primo elemento, facendo attenzione che si evidenzi in questo modo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 84
Per prima cosa impostiamo la classe di questo UIViewController. Andiamo nel pannello “Identity<br />
Inspector” e selezioniamo “PrimaVistaController” come classe:<br />
È molto importante non saltare questo primo passo, altrimenti <strong>per</strong> viste di una certa complessità<br />
riceverete errori strani che non sapete da cosa dipendono, il tutto solamente <strong>per</strong> non aver<br />
impostato la classe della vista!<br />
Poi nel pannello “Attributes Inspector” selezioniamo “PrimaVista” dal menù “NIB Name”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 85
Ora facciamo doppio clic sul nome del tab (che <strong>per</strong> default è “Item”), e rinominiamolo a nostro<br />
piacere. Ripetiamo, poi, lo stesso procedimento con il secondo tab, associando questa volta la<br />
“SecondaVista”.<br />
Se avete eseguito tutto in maniera corretta avrete il seguente risultato:<br />
Chiudiamo ora Interface Builder, salvando tutti i file. Da XCode clicchiamo su “Build and Go!”<br />
e testiamo se tutto funziona in maniera corretta!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 86
PARTE 2: INSERIAMO UNA NAVIGATIONBAR<br />
Nella seconda parte di questo tutorial analizzeremo l’aspetto più importante e più delicato, ovvero<br />
l’implementazione di una UINavigationBar e di una tabella. Questa combinazione ci <strong>per</strong>metterà<br />
di navigare nei sotto-elementi della tabella. Ovvero, quando l’utente seleziona una determinata<br />
cella si aprirà una corrispondente vista che avremo definito con Interface Builder. La<br />
navigation bar, poi, ci <strong>per</strong>metterà di tornare alla tabella principale. Un po’ come avviene nel<br />
menù “Impostazioni” del’<strong>iPhone</strong> / iPod Touch!<br />
CREIAMO UN NUOVO ELEMENTO PER LA TABBAR<br />
Iniziamo creando la classe che gestirà la nuova vista. Dal menù “File” scegliamo “New File…”,<br />
nel pannello che apparirà selezioniamo “UIViewController subclass” e spuntiamo la voce “UI-<br />
TableViewController subclass” presente nelle opzioni. Chiamiamo questa nuova classe “TabellaController”.<br />
Abbiamo già imparato a gestire una tabella nel capitolo 9, quindi non rispiegherò il codice utilizzato.<br />
Riutilizziamo gli stessi metodi, quindi inserite nel file “TabellaController.h” il seguente<br />
codice:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 87
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
#import <br />
@interface TabellaController : UITableViewController {!<br />
! //array che conterrà gli elementi da visualizzare nella tabella<br />
! NSArray *lista;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSArray *lista;<br />
@end<br />
Mentre in “TabellaController.m” inserite questi metodi:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
#import "TabellaController.h"<br />
@implementation TabellaController<br />
@synthesize lista;<br />
- (void)awakeFromNib{!<br />
! // creiamo la lista e inseriamo una serie di elementi da visualizzare<br />
nella nostra tabella<br />
! lista = [[NSArray alloc] initWithObjects:! @"<strong>iPhone</strong>", @"iPod",<br />
@"iPod Touch", @"iMac", @"iBook", @"MacBook", @"MacBook Pro", @"Mac<br />
Pro", @"PowerBook", nil];<br />
}<br />
//setta il numero di sezioni della tabella<br />
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{<br />
! return 1;<br />
}<br />
//setta il numero di righe della tabella<br />
- (NSInteger)tableView:(UITableView *)tableView<br />
numberOfRowsInSection:(NSInteger)section{<br />
! //numero di righe deve corrispondere al numero di elementi della<br />
lista<br />
! return [lista count];<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 88
22<br />
23<br />
24<br />
25<br />
26<br />
27<br />
28<br />
29<br />
30<br />
31<br />
32<br />
33<br />
34<br />
35<br />
//settiamo il contenuto delle varie celle<br />
- (UITableViewCell *)tableView:(UITableView *)tableView<br />
cellForRowAtIndexPath:(NSIndexPath *)indexPath{<br />
!<br />
! UITableViewCell *cell = [tableView<br />
dequeueReusableCellWithIdentifier:@"cellID"];<br />
!<br />
! if (cell == nil){<br />
! ! cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero<br />
reuseIdentifier:@"cellID"] autorelease];<br />
! !<br />
! }<br />
! //inseriamo nella cella l'elemento della lista corrispondente<br />
! cell.textLabel.text = [lista objectAtIndex:indexPath.row];<br />
!<br />
! return cell;<br />
}<br />
Salviamo entrambi i file e riapriamo “MainWindow.xib” <strong>per</strong> tornare in Interface Builder.<br />
DEFINIAMO L’ASPETTO DEL NUOVO ELEMENTO<br />
Dalla Libreria prendiamo un componente UINavigationController e inseriamolo nella tab bar,<br />
proprio come abbiamo nella prima parte di questo tutorial.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 89
Proprio come abbiamo fatto in precedenza cambiamo il nome della scheda in “Tabella”. Ecco il<br />
risultato finale:<br />
Ora non ci resta che inserire la tabella all’interno di questa vista. Dalla Libreria prediamo un<br />
componente UITableViewController e inseriamolo nella nostra vista. Il risultato che dovete<br />
ottenere è il seguente:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 90
Ora dobbiamo solo collegare la classe alla tabella appena inserita. Dal Pannello dei Documenti<br />
(”Tools -> Reveal in Document Window”) navighiamo fino al seguente <strong>per</strong>corso:<br />
Come mostrato in figura, selezioniamo il componente “Table View Controller” (che non è altro<br />
che la nostra tabella) e apriamo l’”Identity Inspector”. Dal menù Class scegliamo “TabellaController”:<br />
Abbiamo così concluso con la creazione della nostra tabella. Salviamo tutto, torniamo in XCode<br />
e clicchiamo su “Build and Go!”: la tabella sarà ora presente e funzionante nell’applicazione!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 91
IMPLEMENTIAMO DUE VISTE DI DETTAGLIO<br />
Ora vediamo di analizzare un aspetto che molti utenti mi hanno chiesto via mail. Se noi volessimo<br />
associare un determinato file “xib” (ovvero creato con Interface Builder) ad una cella, come<br />
potremmo fare? In questa seconda parte del tutorial vedremo proprio di analizzare i passaggi<br />
necessari. Andremo a definire due viste, una che conterrà una foto dell’elemento “<strong>iPhone</strong>”,<br />
mentre un’altra che avviserà l’utente dell’assenza di informazioni <strong>per</strong> un determinato prodotto.<br />
Ovviamente potreste realizzare una vista con i dettagli <strong>per</strong> ogni prodotto presente nella<br />
tabella, ma il meccanismo rimane invariato.<br />
Iniziamo creando due nuovi file xib, dal menù “File -> New File…” e scegliendo “Empty XIB”.<br />
Io ho chiamato il primo file “<strong>iPhone</strong>Detail” e il secondo “OtherDetail”, ma nulla vieta di chiamarli<br />
in modo diverso!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 92
Procediamo proprio come abbiamo fatto all’inizio dello scorso tutorial <strong>per</strong> le viste “PrimaVista”<br />
e “Seconda Vista”, quindi definiamo subito via codice le due classi necessarie.<br />
Andiamo, quindi, in “File -> New File…” e spostiamoci nella sezione “Cocoa Touch Class”, in<br />
cui selezioniamo il modello “UIViewController”: anche in questo caso dobbiamo creare due<br />
classi, chiamate “<strong>iPhone</strong>DetailController” e “OtherDetailController”.<br />
Possiamo spostare i file appena creati nella sezione “Classes” del nostro progetto. Ora siamo<br />
pronti <strong>per</strong> definire l’aspetto di queste due nuove viste.<br />
DEFINIAMO L’ASPETTO DELLE DUE VISTE DI DETTAGLIO<br />
Apriamo il file “<strong>iPhone</strong>Detail.xib” in Interface Builder. Il procedimento è, come già detto,<br />
uguale a quello svolto <strong>per</strong> la definizione delle due viste “PrimaVista” e “SecondaVista”. Inseriamo,<br />
quindi, un componente UIView nel Pannello dei Documenti e modifichiamolo a nostro<br />
piacimento. Io ho inserito una foto di un <strong>iPhone</strong>, ovviamente voi potrete inserire quello che<br />
volete. Ecco come risulta essere la mia vista:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 93
Ora associamo questa vista alla sua classe. Dal Pannello dei Documenti selezioniamo il “File’s<br />
Owner” e nell’”Identity Inspector” selezioniamo “<strong>iPhone</strong>DetailController” come classe:<br />
Andiamo poi in “Connections Inspector” e colleghiamo l’elemento “view” con la vista che abbiamo<br />
appena creato (quella contenente le due label <strong>per</strong> intenderci). Se abbiamo eseguito il<br />
passaggio in maniera corretta avremo questo risultato:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 94
Abbiamo così completato la definizione della vista. Eseguiamo lo stesso procedimento anche<br />
<strong>per</strong> il file “OtherDetail.xib”, collegandola <strong>per</strong>ò alla classe “OtherDetailController”. Ecco come<br />
appare tale vista:<br />
Possiamo salvare tutto e chiudere Interface Builder.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 95
COME RICHIAMARE LE DUE VISTE VIA CODICE<br />
Ora non ci resta che analizzare il codice che ci <strong>per</strong>mette di aprire queste due viste. Apriamo il<br />
file “TabellaController.h” e modifichiamolo nella seguente maniera:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
#import <br />
#import "<strong>iPhone</strong>DetailController.h"<br />
#import "OtherDetailController.h"<br />
@interface TabellaController : UITableViewController {!<br />
! //array che conterrà gli elementi da visualizzare nella tabella<br />
! NSArray *lista;<br />
! //controller della vista che dovrà essere a<strong>per</strong>ta<br />
! UIViewController *detail;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSArray *lista;<br />
@end<br />
Abbiamo <strong>per</strong> prima cosa importato le due classi delle viste (righe 2 e 3), e poi definito una vista<br />
generica (riga 10), che poi inizializzeremo con la classe “<strong>iPhone</strong>DetailController” oppure “OtherDetailController”,<br />
a seconda del caso. Perché abbiamo utilizzato “UIViewController” come<br />
tipo dell’elemento “detail”? Perchè abbiamo sfruttato un paradigma della programmazione ad<br />
oggetti, che ci <strong>per</strong>mette di definire un elemento con una su<strong>per</strong>classe, <strong>per</strong> poi inizializzarlo con<br />
una sottoclasse più specifica.<br />
Ora apriamo il file “TabellaController.m” e inseriamo il metodo che viene richiamato quando si<br />
clicca su una cella:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 96
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
// Metodo relativo alla selezione di una cella<br />
- (void)tableView:(UITableView *)tableView<br />
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {<br />
!<br />
! if (indexPath.row == 0){<br />
! ! //l'utente ha cliccato sull'elemento <strong>iPhone</strong>, quindi carichiamo<br />
la vista relativa<br />
! ! detail = [[<strong>iPhone</strong>DetailController alloc]<br />
initWithNibName:@"<strong>iPhone</strong>Detail" bundle:[NSBundle mainBundle]];<br />
! } else {<br />
! ! detail = [[OtherDetailController alloc]<br />
initWithNibName:@"OtherDetail" bundle:[NSBundle mainBundle]];<br />
! }<br />
!<br />
! //Facciamo visualizzare la vista con i dettagli<br />
! [self.navigationController pushViewController:detail<br />
animated:YES];<br />
! //rilasciamo il controller<br />
! [detail release];<br />
!<br />
! detail = nil;<br />
}<br />
Anche questo metodo lo avevamo già trovato nel tutorial dedicato alle tabelle. Analizziamo,<br />
<strong>per</strong>ò, il codice al suo interno. Troviamo inizialmente un controllo if (riga 4), che controlla se<br />
l’utente ha selezionato al prima cella, ovvero quella contenente l’elemento <strong>iPhone</strong>: se il controllo<br />
da esito positivo, inizializziamo l’elemento “detail” con la classe relativa alla vista “<strong>iPhone</strong>-<br />
Detail” (riga 6), altrimenti con l’altra vista generica (riga 8). La clausola “initWithNibName” si<br />
riferisce proprio al file xib che deve essere associato all’elemento “detail”.<br />
Dopo il ciclo troviamo le istruzioni che ci <strong>per</strong>mettono di far apparire la nuova vista; non<br />
preoccupatevi troppo, sono sempre queste istruzioni da utilizzare.<br />
Abbiamo concluso!! Clicchiamo su “Build and Go!” e godiamoci la nostra applicazione funzionante!!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 97
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 98
Capitolo 12: XML<br />
Dopo aver visto molti componenti, in questo capitolo vedremo come integrare una tecnologia<br />
molto utilizzata, specialmente in ambito web: stiamo parlando di XML.<br />
Vedremo, quindi, come leggere un file XML, da cui ricaveremo delle informazioni che abbiamo<br />
salvato. Questa o<strong>per</strong>azione verrà eseguita in locale (ovvero il file xml sarà all’interno del nostro<br />
progetto), ma nulla vieta di avere il file caricato su un server web da cui accediamo tramite la<br />
nostra applicazione.<br />
COSA È XML?<br />
XML è un metalinguaggio (in quanto non è un linguaggio di programmazione vero e proprio)<br />
di markup, ovvero un linguaggio che consente di estendere o controllare il comportamento di<br />
altri linguaggi. Il linguaggio di markup più famoso è sicuramente l’HTML, che ha molte analogie<br />
con l’XML.<br />
XML è l’acronimo di eXtensible Markup Language, da cui possiamo capire la caratteristica<br />
fondamentale di questo linguaggio: ci <strong>per</strong>mette di creare tag <strong>per</strong>sonalizzati, in base alle proprie<br />
esigenze.<br />
Sarà più semplice comprendere come funziona questo linguaggio mediante un esempio:<br />
La prima riga definisce la versione di XML in uso e la codifica utilizzata (secondo le norme<br />
ISO). Dalla seconda riga in poi, invece, troviamo dei tag <strong>per</strong>sonalizzati, che vanno a modellare<br />
dei dati a nostro piacimento.<br />
Possiamo vedere come abbiamo definito un tag generale “studenti”, che viene iniziato alla seconda<br />
riga e concluso all’ultima. Nel mezzo troviamo, invece, altri tag, che riportano le informazioni<br />
che vogliamo memorizzare, <strong>per</strong> poi utilizzarle a nostro piacimento.<br />
Ci sono alcune piccole regole da rispettare nella struttura XML:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 99
1. I tag non possono iniziare con numeri o caratteri speciali e non possono contenere spazi.<br />
Corretti: , , <br />
Errati: , , <br />
2. I tag devono essere bilanciati (ogni tag a<strong>per</strong>to deve essere chiuso)<br />
Corretto: Andrea<br />
Errato: Andrea<br />
3. I tag non devono contenere errori di annidamento.<br />
Ecco alcuni esempi errati:<br />
4. Si possono inserire degli attributi all’interno dei tag; la struttura sarà quindi la seguente:<br />
Valore <br />
I nostri elementi, quindi, potranno essere scritti anche nella seguente maniera:<br />
Questa struttura è del tutto uguale a quella precedente. Notate che in questo caso non abbiamo<br />
usato il tag di chiusura, ma abbiamo inserito “/” all’interno del tag stesso proprio <strong>per</strong><br />
indicare che quel tag non ha elemento di chiusura. Quello che cambierà sarà solamente il<br />
modo di leggere i valori via codice.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 100
XML NEL <strong>SDK</strong> DI IPHONE<br />
Per ora abbiamo fatto una panoramica su XML in generale, presentando gli aspetti fondamentali<br />
di tale linguaggio. Ma come possiamo integrarlo con le nostre applicazioni? L’oggetto che si<br />
occupa di recu<strong>per</strong>are i dati da un file XML viene detto parser.<br />
Esistono vari tipi di parser (diversi <strong>per</strong> linguaggi e tecnologie), noi andremo ad utilizzare SAX.<br />
La caratteristica di questo parser sta nel fatto che processa i documenti linea <strong>per</strong> linea: dati a<br />
cui si è acceduto in precedenza non possono essere riletti senza la rielaborazione dell’intero<br />
documento. Può essere uno svantaggio, ma è l’unico parser disponibile nel <strong>SDK</strong> <strong>per</strong> <strong>iPhone</strong>!!<br />
CREIAMO LA STRUTTURA GRAFICA<br />
Iniziamo ora a creare la nostra applicazione. Creiamo un nuovo progetto di tipo “View-Based<br />
Application” e chiamiamolo “xml<strong>Tutorial</strong>”.<br />
Prima di definire l’aspetto grafico, <strong>per</strong>ò, dichiariamo i componenti che ci servono. Apriamo il<br />
file “xml<strong>Tutorial</strong>ViewController.h” e modificatelo così:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
#import <br />
@interface xml<strong>Tutorial</strong>ViewController : UIViewController <br />
{<br />
! IBOutlet UITextView *textArea;<br />
!<br />
! NSString *path;<br />
}<br />
-(IBAction)avviaParsing;<br />
@end<br />
Abbiamo dichiarato una TextView in cui inseriremo i dati letti dal file xml, un’azione, che andrà<br />
collegata ad un bottone (tale azione farà iniziare il processo di parsing) e una stringa che<br />
conterrà il <strong>per</strong>corso del file xml. Possiamo salvare il file e dedicarci alla struttura grafica dell’applicazione.<br />
Ricordatevi, anche, di inserire nell’intestazione della classe il delegato<br />
“NSXMLParserDelegate” (riga 3).<br />
Apriamo ora il file “xml<strong>Tutorial</strong>ViewControlle.xib”, che avvierà Interface Builder. Nella nostra<br />
applicazione, inseriamo un bottone e una TextView, di dimensioni abbastanza ampie, in quanto<br />
dovrà contenere tutti i valori letti dal file xml. Dovreste ottenere un risultato come questo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 101
Ora, selezionando la UITextView, entriamo in “Attributes Inspector” e togliamo la spunta a<br />
“Editable”:<br />
questo <strong>per</strong>ché non vogliamo che l’utente possa modificare i valori presenti nella TextView (ovvero<br />
deve essere di sola lettura).<br />
Dal pannello dei documenti (”Tools -> Reveal in Document Window”) selezioniamo “File’s<br />
Owner”, ovvero la classe che gestisce il nostro file.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 102
Apriamo il “Connections Inspector” e potremo vedere alcuni elementi, più i due che abbiamo<br />
definito noi all’inizio del nostro progetto. Colleghiamo “textArea” con la UITextView presente<br />
nella nostra vista, e l’azione “avviaParsing” con il bottone: quando apparirà il menù con tutte le<br />
azioni disponibili, scegliamo “Touch Up Inside”. Se avrete eseguito tutto correttamente avrete<br />
un pannello che si presenterà così:<br />
Abbiamo terminato la creazione della struttura grafica. Possiamo salvare tutto e chiudere Interface<br />
Builder.<br />
SCRIVIAMO IL CODICE NECESSARIO<br />
Prima di procedere con il codice necessario, dobbiamo inserire all’interno del progetto il file<br />
xml con i nostri dati. Trascinate il file xml (che potete creare ex-novo, oppure creare copiando il<br />
codice presentato nella prima parte di questo tutorial tutorial) all’interno della cartella “Resources”<br />
del nostro progetto, spuntando l’opzione <strong>per</strong> copiarlo nella cartella fisica del progetto:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 103
Apriamo ora il file “xml<strong>Tutorial</strong>ViewController.m” e definiamo il seguente metodo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
// Metodo eseguito all'avvio della vista<br />
- (void)viewDidLoad {<br />
[su<strong>per</strong> viewDidLoad];<br />
! // definiamo il <strong>per</strong>corso del file xml<br />
! NSString *pathProgetto = [[NSBundle mainBundle] bundlePath];<br />
! path = [[NSString alloc] initWithString:[pathProgetto<br />
stringByAppendingPathComponent:@"dati.xml"]];<br />
}<br />
Questo metodo viene eseguito all’avvio della vista, e ci <strong>per</strong>mette di definire dei comportamenti<br />
che devono essere eseguiti prima di ogni altra cosa. Con le due istruzioni che abbiamo inserito<br />
definiamo il <strong>per</strong>corso del nostro file “dati.xml”: esso viene cercato all’interno della cartella del<br />
nostro progetto. Queste istruzioni sono molto importanti, in quanto non viene definito un<br />
<strong>per</strong>corso assoluto (soluzione sempre sconsigliabile e spesso errata), ma viene definito il <strong>per</strong>corso<br />
effettivo in cui si trova il file.<br />
Dobbiamo ora definire l’azione che viene eseguita quando premiamo sul pulsante. Ecco il codice<br />
da inserire:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 104
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
-(IBAction)avviaParsing{<br />
! //Bisogna convertire il file in una NSURL altrimenti non funziona<br />
! NSURL *xmlURL = [NSURL fileURLWithPath:path];<br />
! // Creiamo il parser<br />
! NSXMLParser *parser = [[ NSXMLParser alloc]<br />
initWithContentsOfURL:xmlURL];<br />
! // Il delegato del parser e' la classe stessa (self)<br />
! [parser setDelegate:self];<br />
! //Effettuiamo il parser<br />
! BOOL success = [parser parse];<br />
! //controlliamo come è andata l'o<strong>per</strong>azione<br />
! if(success == YES){<br />
! ! //parsing corretto<br />
! } else {<br />
! ! //c'è stato qualche errore...<br />
! }<br />
! // Rilasciamo l'oggetto NSXMLParser<br />
! [parser release];<br />
}<br />
Le istruzioni alle righe 3 e 5 ci <strong>per</strong>mettono di definire il parser, partendo dal <strong>per</strong>corso del nostro<br />
file. Alla riga 9 avviamo il processo di parsing, salvando il risultato in una variabile booleana:<br />
se essa vale YES la conversione si è conclusa senza errori (riga 12), altrimenti c’è stato un<br />
errore (che potrebbe essere dovuto ad errori nella struttura del file xml oppure ad errori di<br />
scrittura del codice).<br />
Come potete vedere non si tratta di codice complesso, sono poche istruzioni che dovrebbero<br />
risultarvi chiare.<br />
La parte che viene ora è quella che si occupa di leggere i dati dal file xml. Iniziamo inserendo<br />
questo metodo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 105
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName<br />
namespaceURI:(NSString *)namespaceURI<br />
qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary<br />
*)attributeDict {<br />
!<br />
! if ([elementName isEqualToString:@"studenti"]){<br />
! ! [textArea setText:[[NSString alloc]<br />
initWithFormat:@"%@\nInizio studenti",textArea.text]];<br />
! }<br />
! else if([elementName isEqualToString:@"studente"]){<br />
! ! [textArea setText:[[NSString alloc]<br />
initWithFormat:@"%@\nNuovo studente",textArea.text]];<br />
! }<br />
! else if([elementName isEqualToString:@"matricola"]) {<br />
! ! [textArea setText:[[NSString alloc]<br />
initWithFormat:@"%@\nMatricola: ",textArea.text]];<br />
! }<br />
! else if([elementName isEqualToString:@"cognome"]) {<br />
! ! [textArea setText:[[NSString alloc]<br />
initWithFormat:@"%@\nCognome: ",textArea.text]];<br />
! }!<br />
! else if([elementName isEqualToString:@"nome"]) {<br />
! ! [textArea setText:[[NSString alloc]<br />
initWithFormat:@"%@\nNome: ",textArea.text]];<br />
! }<br />
}<br />
Come potete osservare, vi sono una serie di controlli if, che vanno a testare l’elemento corrente,<br />
<strong>per</strong> riconoscerlo e <strong>per</strong> scrivere una stringa adeguata nella textArea che abbiamo predisposto.<br />
Questo processo è possibile <strong>per</strong>ché conosciamo a priori la struttura del file xml: questo è quasi<br />
sempre vero, in quanto sarebbe quasi impossibile leggere un file xml di cui non conosciamo la<br />
struttura interna.<br />
Il metodo viene, ovviamente, richiamato ogni volta che il parser incontra un nuovo elemento,<br />
cioè l’a<strong>per</strong>tura di un tag.<br />
Per completare il nostro programma mancano solo due metodi:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString<br />
*)string {<br />
! [textArea setText:[[NSString alloc]<br />
initWithFormat:@"%@%@",textArea.text,string]];<br />
}<br />
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName<br />
namespaceURI:(NSString *)namespaceURI<br />
qualifiedName:(NSString *)qName {<br />
! [textArea setText:[[NSString alloc] initWithFormat:@"%@\nFine<br />
elemento: %@",textArea.text,elementName]];<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 106
Il primo viene richiamato quando il parser incontra un valore racchiuso tra due tag (l’informazione<br />
vera e propria). Nel nostro caso ci limitiamo a inserirla nella textArea, <strong>per</strong>ò potreste fare<br />
delle o<strong>per</strong>azioni più o meno complesse sulle informazioni che leggete dal file.<br />
L’ultimo metodo, invece, viene richiamato quando il parser incontra un tag di chiusura. Anche<br />
in questo caso l’unica azione che faremo sarà quello di inserire una stringa nella textArea.<br />
Possiamo finalmente cliccare su “Build and Go!” e testare la nostra applicazione funzionante!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 107
Capitolo 13: SQL<br />
Nel capitolo precedente abbiamo visto come leggere un file XML e fare il parsing dei dati contenuti<br />
al suo interno. Non esiste, <strong>per</strong>ò, solo quella possibilità <strong>per</strong> accedere ad un archivio di dati.<br />
La tecnologia di maggior successo è sicuramente SQL, che si basa su database relazionali. In<br />
questo capitolo vedremo come sfruttare SQLite <strong>per</strong> interfacciarci con un database presente in<br />
locale (quindi salvato all’interno del nostro progetto). Nulla vieta, <strong>per</strong>ò, che il database risieda<br />
su un server remoto, e che quindi la connessione avvenga tramite la rete.<br />
Creeremo, quindi, una tabella in cui andremo ad inserire i valori letti dal nostro database, dopo<br />
aver eseguito una query predefinita.<br />
Devo premettere, <strong>per</strong>ò, che non parlerò di SQL e database relazionali, che devono essere già<br />
conosciuti da chi affronta questo capitolo. È una scelta che potrebbe non piacere a molti di voi,<br />
<strong>per</strong>ò richiederebbe troppo tempo e una trattazione che non può essere fatta in un semplice tutorial.<br />
Detto ciò, è possibile seguire questa guida e concludere con successo l’applicazione, anche<br />
senza conoscere niente di SQL, ovviamente alcune caratteristiche e alcuni passaggi potrebbero<br />
risultare di difficile comprensione.<br />
In questa guida sentirete spesso parlare di SQLite, ma cosa è di preciso?<br />
SQLite è una libreria che implementa un DBMS SQL, <strong>per</strong>mettendo di creare un database all’interno<br />
di un unico file. Esso è molto indicato <strong>per</strong> scopi come il nostro, ovvero la creazione di<br />
applicazioni <strong>per</strong> dispositivi mobili, che non possono <strong>per</strong>mettersi di avere un DMBS dedicato<br />
<strong>per</strong> la gestione delle basi di dati.<br />
Ovviamente fornisce un supporto parziale all’SQL, in quanto manca di alcune caratteristiche<br />
avanzate, che <strong>per</strong>ò dubito possiate utilizzare all’interno di un’applicazione. SQLite, comunque,<br />
è molto veloce e leggero, <strong>per</strong>fetto quindi <strong>per</strong> applicazioni <strong>per</strong> <strong>iPhone</strong>.<br />
DEFINIAMO UN NUOVO PROGETTO<br />
Iniziamo creando un nuovo progetto di tipo “Navigation-based Application” e chiamiamolo<br />
“sql<strong>Tutorial</strong>”. Abbiamo quindi creato un progetto che ci fornisce già l’implementazione di una<br />
tabella, che visualizzerà i dati letti dal nostro database.<br />
Dobbiamo, <strong>per</strong>ò, inserire altre due cose molto importanti: una classe che si occu<strong>per</strong>à di comunicare<br />
con il database, e la libreria che <strong>per</strong>mette tale comunicazione.<br />
Iniziamo creando la classe che serirà ai nostri scopi. Andiamo in “File -> New File…” e creiamo<br />
una “Objective-C class”, chiamandola semplicemente “Data”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 108
Dobbiamo ora inserire nel nostro progetto la libreria (o framework) che si occupa del collegamento<br />
con il database sql. Clicchiamo con il tasto destro sulla cartella “Frameworks” all’interno<br />
del nostro progetto, poi andiamo in “Add -> Existing Frameworks…” e dall’elenco seguente che<br />
apparirà selezioniamo “libsqlite3.0.dylib”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 109
Abbiamo così terminato la definizione della struttura principale del nostro progetto. Se avete<br />
eseguito tutto in maniera corretta dovreste avere un progetto come questo:<br />
DEFINIAMO LA CLASSE “DATA”<br />
Dobbiamo ora implementare la classe “Data”, su cui si basa gran parte di questo capitolo. Prima<br />
di iniziare a scrivere codice, focalizziamo l’attenzione su ciò che deve fare questa classe. Essa<br />
avrà il compito di:<br />
• creare una connessione con il database (di cui noi specificheremo un indirizzo, in questo<br />
caso locale, ma nulla vieterebbe di avere un database in remoto);<br />
• interrogare la base di dati eseguendo una query impostata via codice;<br />
• inserire i risultati della query all’interno di un’array, che verrà poi visualizzato all’interno<br />
della tabella.<br />
Vediamo ora di implementare queste funzionalità, più altre caratteristiche che ci serviranno<br />
come supporto.<br />
Iniziamo aprendo il file “Data.h” e inserendo il seguente codice:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 110
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
#import <br />
#import <br />
@interface Data : NSObject {<br />
! // Lista contenente i dati letti dal database<br />
! NSMutableArray *lista;<br />
}<br />
- (id)init:(NSString *)pathDB;<br />
- (void)caricaValoriDaDB:(NSString *)dbPath;<br />
- (unsigned)getSize;<br />
- (id)objectAtIndex:(unsigned)theIndex;<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSMutableArray *lista;<br />
@end<br />
Alla riga numero 6 abbiamo dichiarato un array (di tipo NSMutableArray, quindi modificabile<br />
anche dopo la sua inizializzazione), che conterrà i valori letti dal database. Dalla riga 10 alla 13<br />
abbiamo definito i metodi che ci serviranno in tale classe, che implementeremo fra poco. Da<br />
notare, inoltre, la classe importata alla riga 2: è necessaria <strong>per</strong> dire alla nostra classe di utilizzare<br />
la libreria che abbiamo importato all’inizio della guida.<br />
Apriamo ora il file “Data.m” e iniziamo ad inserire il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
#import "Data.h"<br />
static sqlite3 *database = nil;<br />
@implementation Data<br />
@synthesize lista;<br />
// Inizializziamo l'oggetto della classe Data<br />
- (id)init:(NSString *)pathDB{<br />
! // carichiamo i valori dal database<br />
! [self caricaValoriDaDB:pathDB];<br />
return self;<br />
}<br />
// Ritorna la dimensione della lista (n° di elementi letti dal db)<br />
- (unsigned)getSize {<br />
return [lista count];<br />
}<br />
// Ritorna l'oggetto ad una data posizione<br />
- (id)objectAtIndex:(unsigned)index {<br />
return [lista objectAtIndex:index];<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 111
La prima istruzione particolare compare alla riga 3, ed è la definizione dell’oggetto che ci servirà<br />
<strong>per</strong> creare la connessione con il database.<br />
Alla riga 10 viene dichiarato il primo metodo, “init”, che deve essere invocato quando si vuole<br />
inizializzare un oggetto appartenente alla classe Data. Alla riga 12 viene chiamiamo il metodo<br />
“caricaValoriDaDB”, che ha il compito di interfacciarsi con il database ed eseguire le query sui<br />
dati (vedremo fra poco la sua implementazione). Il “return self” alla riga 13, infine, ritorna il<br />
puntatore dell”oggetto appena creato.<br />
Alla riga 17 definiamo “getSize”, un semplice metodo che ci ritorna la dimensione della lista, e<br />
quindi il numero di elementi letti dalla nostra query. Questo ci servirà quando andremo a definire<br />
la tabella.<br />
Infine, alla riga 22, definiamo un metodo che ci ritorna un oggetto presente ad una determinata<br />
posizione della nostra lista. Ad esempio, potremo recu<strong>per</strong>are il 5° elemento della nostra lista,<br />
<strong>per</strong> poi elaborarlo oppure mostrarlo all’utente.<br />
Dobbiamo ora implementare il metodo più complesso di questa classe, ovvero “caricaValori-<br />
DaDB”. Ecco il codice di tale metodo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 112
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
26<br />
27<br />
28<br />
29<br />
30<br />
31<br />
32<br />
33<br />
34<br />
35<br />
36<br />
// Carica i valori dal database passato come parametro<br />
- (void)caricaValoriDaDB:(NSString *)dbPath {<br />
! NSLog(@"path: %@",dbPath);<br />
! // lista temporanea<br />
! NSMutableArray *listaTemp = [[NSMutableArray alloc] init];<br />
! // Oggetto che contiene i vari elementi<br />
NSMutableDictionary *dictionary;<br />
!<br />
! NSMutableString *idPersona;//id della <strong>per</strong>sona<br />
! NSMutableString *nome;//nome della <strong>per</strong>sona<br />
! NSMutableString *cognome;//cognome della <strong>per</strong>sona<br />
!<br />
! if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {<br />
! ! // query che ricava i valori<br />
! ! const char *sql = "select ID, Nome, Cognome from PERSO-<br />
NA";<br />
! ! sqlite3_stmt *selectstmt;<br />
! !<br />
! ! if(sqlite3_prepare_v2(database, sql, -1, &selectstmt,<br />
NULL) == SQLITE_OK) {<br />
! ! ! while(sqlite3_step(selectstmt) == SQLITE_ROW) {<br />
! ! ! ! // ricaviamo i valori letti dalla query<br />
! ! ! ! idPersona = [NSString<br />
stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 0)];<br />
! ! ! ! nome = [NSString stringWithUTF8String:(char<br />
*)sqlite3_column_text(selectstmt, 1)];<br />
! ! ! ! cognome = [NSString stringWithUTF8String:(char<br />
*)sqlite3_column_text(selectstmt, 2)];<br />
! ! ! ! // inseriamo tutti i valori letti in un unico<br />
oggetto<br />
! ! ! ! dictionary = [[NSMutableDictionary alloc]<br />
initWithObjectsAndKeys:idPersona, @"id", nome, @"nome", cognome,<br />
@"cognome", nil];<br />
! ! ! ! [listaTemp addObject:dictionary];<br />
! ! ! ! [dictionary release];<br />
! ! ! }<br />
! ! }<br />
! ! self.lista = listaTemp;<br />
! ! [listaTemp release];<br />
! }<br />
! else<br />
! ! sqlite3_close(database);<br />
! NSLog(@"tutto ok");<br />
}<br />
Iniziamo ad analizzare questo metodo. Partiamo dall’intestazione, in cui viene definito un parametro<br />
“dbPath”: questo è il <strong>per</strong>corso del nostro database. Esso lo definiremo in seguito, nella<br />
classe che gestisce la tabella. In questo tutorial il database sarà in locale, ovverò sarà fisicamente<br />
presente nella cartella del nostro progetto. Nulla vieta, comunque, di inserire un indirizzo<br />
remoto, che ci consenta di connetterci ad un database presente su un server.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 113
Subito dopo, creiamo alcuni oggetti, che ci servono <strong>per</strong> gestire i dati ricavati dalle query. Abbiamo,<br />
infatti, un oggetto “dictionary”, che conterrà i vari elementi ricavati dall’interrogazione<br />
al database. Le stringhe “idPersona”, “nome”, “cognome”, infatti, servono <strong>per</strong> salvare i valori<br />
letti, e inserirli all’interno dell’oggetto appena menzionato.<br />
Alla riga 13 viene a<strong>per</strong>ta la connessione con il database: essa si trova all’interno di un costrutto<br />
“if”: se tale controllo da esito positivo, si possono elaborare i dati, altrimenti si passa alla fine<br />
del metodo, in quanto non è possibile instaurare una connessione con il database. Se la connessione<br />
è stata creata, possiamo creare la query che andremo poi ad eseguire (riga 15). Alla riga 18<br />
eseguiamo poi tale query: anche in questo caso, se l’esecuzione ha avuto successo, possiamo<br />
ricavare i valori desiderati, altrimenti non verrà eseguita nessuna o<strong>per</strong>azione.<br />
Il ciclo while (riga 19) ci <strong>per</strong>metterà di scorrere tutti i risultati della nostra query (che potrebbero<br />
essere, ovviamente, più di uno), fino al termine. Potete notare che i risultati vengono inseriti<br />
in un oggetto di tipo “NSMutableDictionary”: esso è come un grande contenitore, che ci<br />
<strong>per</strong>mette di inserire valori associandoci un tag (quello che facciamo alla riga 25).<br />
Come vedete non si tratta di o<strong>per</strong>azioni complesse, si tratta solo di capire come funziona il<br />
meccanismo, che potete poi variare a seconda delle vostre esigenze.<br />
Gli ultimi due metodi da inserire nel file “Data.m” sono i seguenti:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
+(void)finalizeStatements {<br />
! if(database)<br />
! ! sqlite3_close(database);<br />
}<br />
-(void)dealloc {<br />
! [lista release];<br />
! [su<strong>per</strong> dealloc];<br />
}<br />
Il primo si occupa di concludere la query e di chiudere la connessione al database (va sempre<br />
messo), mentre il secondo è il classico “dealloc”.<br />
Abbiamo concluso con la definizione della classe “Data”. Ora vedremo come creare il nostro<br />
database e inserirlo nel progetto.<br />
CREIAMO IL DATABASE<br />
Quello che dobbiamo andare a realizzare è un semplice database, con tecnologia SQLite. Per<br />
crearlo utilizzeremo un plug-in <strong>per</strong> Firefox, chiamato” SQLite Manager”, che potete trovare a<br />
questo indirizzo (https://addons.mozilla.org/en-US/firefox/addon/5817). In alternativa esistono<br />
alcuni programmi dedicati, come SQLiteManager (http://www.sqlabs.com/sqlitemanager.php),<br />
che è, <strong>per</strong>ò, a pagamento.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 114
Dopo aver installato l’estensione, andiamo in “Strumenti -> SQLite Manager”, si avvierà il tool<br />
che ci <strong>per</strong>metterà di creare il nostro database. Clicchiamo sull’icona del foglio bianco <strong>per</strong> creare<br />
un nuovo database:<br />
e inseriamo “<strong>per</strong>sone” come nome <strong>per</strong> il file:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 115
e scegliamo dove salvare il file (vi consiglio sulla Scrivania, così potrete recu<strong>per</strong>arlo subito in<br />
seguito).<br />
Abbiamo così creato il nostro database, che risulta <strong>per</strong>ò essere completamente vuoto. Dobbiamo,<br />
quindi, creare la tabella “Persone”. Per fare ciò, facciamo clic con il tasto destro su “Tables”<br />
che trovate nella parte sinistra della schermata, e selezioniamo “Create Table”:<br />
Si aprirà una nuova schermata, in cui dovrete definire gli attributi della tabella. Ecco cosa dovete<br />
inserire:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 116
e clicchiamo poi su “Yes” nel messaggio successivo che apparirà.<br />
Abbiamo inserito gli attributi necessari, ovvero nome, cognome e un identificativo univoco<br />
(id).<br />
Non ci resta che inserire dei valori nella tabella. Per fare ciò, andate nella sezione “Execute<br />
SQL” inserite le seguenti istruzioni:<br />
INSERT INTO PERSONA (id,Nome,Cognome) VALUES ('1','Giovanni','Verdi');<br />
INSERT INTO PERSONA (id,Nome,Cognome) VALUES ('2','Paolo','Rossi');<br />
INSERT INTO PERSONA (id,Nome,Cognome) VALUES ('3','Luca','Bianchi');<br />
INSERT INTO PERSONA (id,Nome,Cognome) VALUES ('4','Andrea','Busi');<br />
Un messaggio in “Last Error” vi comunicherà se vi sono stati errori nell’inserimento dei dati,<br />
oppure se tutto è andato <strong>per</strong> il verso giusto.<br />
Possiamo, infine, controllare i valori che abbiamo inserito, spostandoci nella sezione “Browse<br />
& Search”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 117
Abbiamo concluso! Chiudiamo pure il programmino, i cambiamenti sono già stati apportati al<br />
nostro database.<br />
CONCLUDIAMO L’APPLICAZIONE<br />
Torniamo ora ad XCode, e concludiamo lo sviluppo della nostra applicazione. Per prima cosa,<br />
dobbiamo inserire il database che abbiamo creato nel nostro progetto. Trasciniamo il file all’interno<br />
di XCode:<br />
e nella schermata che apparirà inserite la spunta a “Copy items into destination group’s folder”<br />
e cliccate su “Add”<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 118
Siamo pronti <strong>per</strong> completare la nostra applicazione. Iniziamo aprendo il file<br />
“RootViewController.h” e inseriamo il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
#import "Data.h"<br />
@interface RootViewController : UITableViewController {<br />
! // Oggetto con la lista degli elementi letti dal db<br />
! Data *dataList;<br />
}<br />
@end<br />
Alla riga 5 abbiamo dichiarato la lista che conterrà gli elementi letti dal database. Per capirci, è<br />
quella che viene creata dal metodo “caricaValoriDaDB”, che abbiamo definito in precedenza.<br />
Passiamo ora al file “RootViewController.m”. Iniziamo con il metodo “viewDidLoad”, che, come<br />
ormai dovreste sa<strong>per</strong>e, ci consente di eseguire delle o<strong>per</strong>azioni al caricamento dell’applicazione.<br />
Ecco come dovete modificare tale metodo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
- (void)viewDidLoad {<br />
[su<strong>per</strong> viewDidLoad];<br />
! self.title = @"Lista Autori";<br />
! //leggiamo il path del database<br />
! NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath]<br />
stringByAppendingPathComponent:@"<strong>per</strong>sone.sqlite"];<br />
!<br />
! //creiamo la lista degli autori<br />
! dataList = [[Data alloc] init:defaultDBPath];<br />
}<br />
Alla riga 4 impostiamo il titolo alla nostra tabella, mentre alla riga 6 definiamo il <strong>per</strong>corso del<br />
nostro database. A prima vista può sembrare complessa, ma essa non fa altro che rilevare il <strong>per</strong>corso<br />
in cui si trova l’applicazione (sia essa su <strong>iPhone</strong> Simulator che su <strong>iPhone</strong> fisico) e aggiungere<br />
a tale <strong>per</strong>corso “<strong>per</strong>sone.sqlite”, che è proprio il database che abbiamo inserito nel nostro<br />
progetto.<br />
Alla riga 9, infine, inizializiamo la lista, passando alla funzione “init” proprio il <strong>per</strong>corso che<br />
abbiamo definito poche righe sopra.<br />
Dobbiamo, ora, definire i metodi necessari <strong>per</strong> settare la tabella. Abbiamo già visto questi metodi<br />
nei tutorial dedicati alle TableView, quindi non mi soffermerò troppo sulla spiegazione.<br />
Sempre all’interno del file “RootViewController.m”, scorretelo verso il fondo, e troverete i metodi<br />
del protocollo UITableView, che dovrete completare nel seguente modo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 119
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
26<br />
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {<br />
return 1;<br />
}<br />
// Customize the number of rows in the table view.<br />
- (NSInteger)tableView:(UITableView *)tableView<br />
numberOfRowsInSection:(NSInteger)section {<br />
return [dataList getSize];<br />
}<br />
// Customize the appearance of table view cells.<br />
- (UITableViewCell *)tableView:(UITableView *)tableView<br />
cellForRowAtIndexPath:(NSIndexPath *)indexPath {<br />
static NSString *CellIdentifier = @"Cell";<br />
UITableViewCell *cell = [tableView<br />
dequeueReusableCellWithIdentifier:CellIdentifier];<br />
if (cell == nil) {<br />
cell = [[[UITableViewCell alloc]<br />
initWithStyle:UITableViewCellStyleDefault<br />
reuseIdentifier:CellIdentifier] autorelease];<br />
}<br />
!<br />
! NSDictionary *itemAtIndex = (NSDictionary *)[dataList<br />
objectAtIndex:indexPath.row];<br />
! cell.textLabel.text = [itemAtIndex objectForKey:@"nome"];<br />
}<br />
return cell;<br />
I tre metodi sono i soliti che vanno inseriti quando si lavora con le UITableView. Concentriamoci<br />
un attimo sulle righe 22 e 23. Esse hanno il compito di ricavare un oggetto dalla lista “dataLista”<br />
(che contiene tutti i valori letti da database), <strong>per</strong> estrarne poi il nome desiderato (ovviamente<br />
vengono estratti tutti i nomi, dal primo all’ultimo). Potete vedere che dall’oggetto<br />
“itemAtIndex” viene estratto solo il nome: potremmo creare anche altre combinazioni, ad<br />
esempio con il cognome. Per fare ciò vi basterà modificare la riga 23 ad esempio nel seguente<br />
modo:<br />
1 [itemAtIndex objectForKey:@"cognome"];<br />
Abbiamo concluso la nostra applicazione! Clicchiamo su “Build and Go!” e controlliamo che<br />
funzioni tutto in maniera corretta.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 120
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 121
Parte 2:<br />
semplici applicazioni<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 122
Capitolo 14: Creiamo un semplice lettore di feed RSS<br />
In questa prima applicazione realizzeremo un semplice ma utilissimo lettore di feed RSS. Vedremo,<br />
infatti, come leggere i dati (solitamente degli articoli) di un feed, visualizzandoli in una<br />
tabella.<br />
Per realizzare questo semplice lettore di feed RSS utilizzeremo due aspetti che abbiamo già<br />
visto nei precedenti capitoli: la gestione delle tabelle (capitolo 9) e l’utilizzo di XML (capitolo<br />
12). Gli elementi relativi a questi due aspetti, quindi, non verranno più spiegati in questo capitolo,<br />
ma verranno considerati come già appresi dal lettore. Ci concentreremo, quindi, solo sugli<br />
elementi di rilievo <strong>per</strong> il lettore di feed RSS.<br />
CREIAMO UN NUOVO PROGETTO<br />
Iniziamo creando un nuovo progetto di tipo “Navigation-based Application” e chiamiamolo<br />
“SimpleRSSReader”. Abbiamo così creato il nostro nuovo progetto, che ci fornisce già una<br />
struttura a tabella, ottima <strong>per</strong> il nostro scopo.<br />
Solitamente la prima cosa che facciamo è realizzare la struttura grafica dell’applicazione. Oggi,<br />
<strong>per</strong>ò, non sarà necessario, in quanto XCode ci fornisce già un template predisposto, contenente<br />
una tabella che conterrà gli elementi che andremo a leggere.<br />
Il primo file che andremo a modificare è “RootViewController.h”. Apritelo e, al suo interno,<br />
scrivete il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
@interface RootViewController : UITableViewController {<br />
! // parser XML<br />
! NSXMLParser *rssParser;<br />
! // elenco degli elementi letti dal feed<br />
! NSMutableArray *elencoFeed;<br />
!<br />
! //variabile temporanea <strong>per</strong> ogni elemento<br />
! NSMutableDictionary *item;<br />
!<br />
! // valori dei campi letti dal feed<br />
! NSString *currentElement;<br />
! NSMutableString *currentTitle, *currentDate, *currentSummary,<br />
*currentLink;<br />
}<br />
- (void)parseXMLFileAtURL:(NSString *)URL;<br />
@end<br />
Alla riga 3 abbiamo definito il nostro parser XML, che si occu<strong>per</strong>à di leggere il feed RSS e di<br />
convertirne gli elementi. Alla riga 5 è definito un NSMutableArray, ovvero una collezione di<br />
oggetti, in cui inseriremo i vari feed letti (con le varie informazioni, ovvero titolo, data, testo,<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 123
etc). Le dichiarazioni alle righe 8, 11 e 12 servono proprio <strong>per</strong> i metodi del parser, sono i valori<br />
che vengono letti e che devono essere inseriti in un unico elemento (“item”), che andrà poi a<br />
comporre la lista degli elementi letti (“elencoFeed”).<br />
Apriamo, ora, il file “RootViewController.m”, in cui troverete già i metodi necessari <strong>per</strong> la definizione<br />
della tabella. Iniziamo a modificare i metodi già presenti, modificandoli a seconda<br />
delle nostre necessità.<br />
Il primo metodo da modificare è il seguente:<br />
1<br />
2<br />
3<br />
- (NSInteger)tableView:(UITableView *)tableView<br />
numberOfRowsInSection:(NSInteger)section {<br />
return [elencoFeed count];<br />
}<br />
Come già sapete, questo metodo imposta il numero di righe della nostra tabella. Tale numero<br />
deve essere pari al numero di elementi che scarichiamo dal feed RSS. Ad esempio, se abbiamo<br />
ricavato 10 notizie dal nostro feed, dovranno essere 10 le righe della tabella, ovvio vero?<br />
Dobbiamo ora modificare il metodo che si occupa di inserire il testo all’interno delle varie celle.<br />
Ecco il metodo che si occupa di ciò:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
- (UITableViewCell *)tableView:(UITableView *)tableView<br />
cellForRowAtIndexPath:(NSIndexPath *)indexPath {<br />
static NSString *CellIdentifier = @"Cell";<br />
UITableViewCell *cell = [tableView<br />
dequeueReusableCellWithIdentifier:CellIdentifier];<br />
if (cell == nil) {<br />
cell = [[[UITableViewCell alloc]<br />
initWithStyle:UITableViewCellStyleDefault<br />
reuseIdentifier:CellIdentifier] autorelease];<br />
}<br />
!<br />
! // Configure the cell.<br />
! cell.textLabel.text = [[elencoFeed objectAtIndex:indexPath.row]<br />
objectForKey:@"title"];<br />
!<br />
! return cell;<br />
}<br />
Troverete anche questo metodo già definito, dovrete solo aggiungere l’istruzione alla riga 11.<br />
Tale istruzione va a ricavare l’elemento desiderato dalla lista (che coincide con il numero di riga,<br />
ricavato da “indexPath.row”), estrae il campo “title” (ovvero il titolo di ogni singolo elemento<br />
del feed RSS che avremo scaricato) e lo setta come contenuto della cella.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 124
Se provassimo ad eseguire il programma adesso, vedremmo che non farebbe ancora niente.<br />
Non abbiamo, infatti, ancora aggiunto la possibilità di scaricare il feed e di utilizzarlo. Quindi<br />
ora facciamo proprio questo.<br />
DEFINIAMO LE AZIONI DEL PARSER<br />
Ci siamo occupati, fino ad ora, solo della definizione della tabella. Non abbiamo ancora visto<br />
nessun aspetto relativo al parser XML.<br />
Iniziamo, quindi, dal metodo “viewDidLoad” (lo trovate commentato nelle prime righe della<br />
classe):<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
- (void)viewDidLoad {<br />
[su<strong>per</strong> viewDidLoad];<br />
! self.title = @"BubiDevs";<br />
!<br />
! NSString *path = @"http://feeds.feedburner.com/TheBubiDevs";<br />
! [self parseXMLFileAtURL:path];<br />
!<br />
// Uncomment the following line to display an Edit button in the<br />
navigation bar for this view controller.<br />
// self.navigationItem.rightBarButtonItem = self.editButtonItem;<br />
}<br />
Come vedete abbiamo aggiunto alcune istruzioni. Alla riga 4 abbiamo settato un titolo alla nostra<br />
applicazione, che comparirà nella navigation bar sopra la tabella. Alla riga 6, invece, viene<br />
definita, una stringa “path”, in cui inseriamo l’indirizzo del feed RSS che vogliamo leggere. In<br />
questo caso io ho inserito l’indirizzo del feed del mio blog, BubiDevs, nulla vi vieta di inserire<br />
l’indirizzo del vostro feed preferito (s<strong>per</strong>iamo che sia uguale al mio! ;-) ). Alla riga successiva,<br />
infine, avviamo il parsing del feed (tramite il metodo “parseXMLFileAtURL”, di cui abbiamo<br />
definito l’intestazione nel file “RootViewController.h”), passando proprio l’indirizzo “path”<br />
come parametro.<br />
Tale metodo, <strong>per</strong>ò, non è ancora stato implementato nella nostra funzione. Ecco, quindi, come<br />
dovrete definirlo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 125
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
- (void)parseXMLFileAtURL:(NSString *)URL {<br />
! // inizializziamo la lista degli elementi<br />
! elencoFeed = [[NSMutableArray alloc] init];<br />
!<br />
! // dobbiamo convertire la stringa "URL" in un elemento "NSURL"<br />
! NSURL *xmlURL = [NSURL URLWithString:URL];<br />
!<br />
! // inizializziamo il nostro parser XML<br />
! rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];<br />
!<br />
! [rssParser setDelegate:self];<br />
!<br />
! // settiamo alcune proprietà<br />
! [rssParser setShouldProcessNamespaces:NO];<br />
! [rssParser setShouldReportNamespacePrefixes:NO];<br />
! [rssParser setShouldResolveExternalEntities:NO];<br />
!<br />
! // avviamo il parsing del feed RSS<br />
! [rssParser parse];<br />
}<br />
Come vedete il metodo non è molto complicato. I commenti presenti vi possono chiarire le<br />
varie istruzioni. Si parte dall’inizializzazione dell’array “elencoFeed” (riga 3), <strong>per</strong> poi passare all’inizializzazione<br />
del parser XML (riga 6) e al suo avvio (riga 19).<br />
Per funzionare correttamente, il parser ha bisogno di altri due metodi. Eccoveli (anche questi<br />
sono da inserire in “RootViewController.m”):<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 126
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
26<br />
27<br />
28<br />
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName<br />
namespaceURI:(NSString *)namespaceURI<br />
qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{!<br />
! !<br />
! currentElement = [elementName copy];<br />
! if ([elementName isEqualToString:@"item"]) {<br />
! ! // inizializza tutti gli elementi<br />
! ! item = [[NSMutableDictionary alloc] init];<br />
! ! currentTitle = [[NSMutableString alloc] init];<br />
! ! currentDate = [[NSMutableString alloc] init];<br />
! ! currentSummary = [[NSMutableString alloc] init];<br />
! ! currentLink = [[NSMutableString alloc] init];<br />
! }<br />
}<br />
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName<br />
namespaceURI:(NSString *)namespaceURI<br />
qualifiedName:(NSString *)qName{<br />
!<br />
! if ([elementName isEqualToString:@"item"]) {<br />
! ! /* salva tutte le proprietà del feed letto nell'elemento<br />
"item", <strong>per</strong><br />
! ! poi inserirlo nell'array "elencoFeed" */<br />
! ! [item setObject:currentTitle forKey:@"title"];<br />
! ! [item setObject:currentLink forKey:@"link"];<br />
! ! [item setObject:currentSummary forKey:@"summary"];<br />
! ! [item setObject:currentDate forKey:@"date"];<br />
! !<br />
! ! [elencoFeed addObject:[item copy]];<br />
! }<br />
}<br />
Questi due metodi vengono richiamati, rispettivamente, quando inizia e quando finisce un<br />
elemento XML. Nel primo caso dovremo re-inizializzare tutti gli elementi, in modo da poter<br />
leggere un nuovo elemento senza errori. Al contrario, quando un elemento XML termina dovremo<br />
salvare tutti questi valori letti in un unico elemento (“item”) e inserirlo nella lista dei<br />
feed letti (“elencoFeed”).<br />
Per completare la definizione del parser ci mancano solo due metodi:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 127
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString<br />
*)string{;<br />
! // salva i caratteri <strong>per</strong> l'elemento corrente<br />
! if ([currentElement isEqualToString:@"title"]){<br />
! ! [currentTitle appendString:string];<br />
! } else if ([currentElement isEqualToString:@"link"]) {<br />
! ! [currentLink appendString:string];<br />
! } else if ([currentElement isEqualToString:@"description"]) {<br />
! ! [currentSummary appendString:string];<br />
! } else if ([currentElement isEqualToString:@"pubDate"]) {<br />
! ! [currentDate appendString:string];<br />
! }<br />
}<br />
- (void) parserDidEndDocument:(NSXMLParser *)parser {<br />
! [self.tableView reloadData];<br />
}<br />
Il primo metodo viene richiamato ogni volta che viene letto un carattere all’interno del feed. A<br />
seconda dell’elemento che siamo considerando, andremo a inserire il carattere letto in coda a<br />
quelli già letti dello stesso carattere, in modo da ricostruire l’informazione completa. Ad esempio,<br />
stiamo considerando l’elemento “title”. Vengono letti, nell’ordine, i seguenti caratteri<br />
“Dev”, “<strong>Tutorial</strong> “, “#2ʺ″. Unendo i vari caratteri letti ricostruiremo il titolo esatto del nostro<br />
feed, ovvero “Dev<strong>Tutorial</strong> #2ʺ″.<br />
Il secondo metodo, invece, viene richiamato solo quando il parser completa la lettura del feed<br />
RSS, e noi non faremo altro che dire alla tabella di ricarcarsi (verranno, quindi, richiamati i metodi<br />
<strong>per</strong> settare il numero di righe e <strong>per</strong> inserire il testo nelle varie celle).<br />
CONCLUDIAMO L’APPLICAZIONE<br />
Abbiamo ormai concluso la nostra applicazione!!<br />
Come sempre dobbiamo ricordarci di completare il metodo “dealloc”, che è davvero molto importante,<br />
soprattutto nelle applicazioni di un certo grado di complessità. Ecco come dovrete<br />
definire il metodo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
- (void)dealloc {<br />
! [currentElement release];<br />
! [rssParser release];<br />
! [elencoFeed release];<br />
! [item release];<br />
! [currentTitle release];<br />
! [currentDate release];<br />
! [currentSummary release];<br />
! [currentLink release];<br />
!<br />
[su<strong>per</strong> dealloc];<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 128
Ora siamo pronti <strong>per</strong> compilare ed eseguire la nostra applicazione! Cliccate su “Build and Run!”<br />
e testare il vostro <strong>per</strong>sonalissimo lettore di feed RSS!!<br />
UN PICCOLO MIGLIORAMENTO<br />
La nostra applicazione funziona ma.. provate a cliccare su un elemento. Non succederà niente.<br />
Non sarebbe invece più carino se si aprisse la pagina in Safari che ci <strong>per</strong>metta di leggere l’intera<br />
notizia?<br />
È presto fatto! Sempre all’interno di “RootViewController.m” cercate il metodo “tableView:<br />
didSelectRowAtIndexPath:” (è uno di quelli commentati di cui vi avevo accennato prima).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 129
Questo metodo viene richiamato ogni volta che si “clicca” su una cella. Sarà qui che andremo<br />
ad inserire il codice necessario:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
- (void)tableView:(UITableView *)tableView<br />
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {<br />
! // ricaviamo il link dell'elemento selezionato<br />
! NSString *link = [[elencoFeed objectAtIndex:indexPath.row] objectForKey:<br />
@"link"];<br />
!<br />
! // ripuliamo il link da spazi, return e tabs<br />
! link = [link stringByReplacingOccurrencesOfString:@" "<br />
withString:@""];<br />
! link = [link stringByReplacingOccurrencesOfString:@"\n"<br />
withString:@""];<br />
! link = [link stringByReplacingOccurrencesOfString:@"! "<br />
withString:@""];<br />
!<br />
! // apriamo la notizia in Safari<br />
! [[UIApplication sharedApplication] openURL:[NSURL<br />
URLWithString:link]];<br />
}<br />
Il procedimento è molto simile a quello visto <strong>per</strong> la definizione delle celle della tabella. Alla riga<br />
4, infatti, andiamo a ricavare la proprietà “link” dell’elemento selezionato, associandola ad<br />
una stringa chiamata appunto “link”. Con le istruzioni seguenti, invece, ripuliamo l’indirizzo da<br />
eventuali caratteri indesiderati, come spazi, return o tab. Con l’istruzione alla riga 12, infine,<br />
apriamo Safari passandogli come parametro proprio il link da noi voluto (che deve essere trasformato<br />
in un NSURL). Fatto!<br />
Salvate il tutto, cliccate su “Build and Run” e godetevi la vostra bellissima applicazione!!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 130
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 131
Capitolo 15: Creiamo un client <strong>per</strong> Twitter!<br />
Attenzione: recentemente Twitter ha cambiato le modalità di accesso, abbandonando le API<br />
che vengono sfruttate in questo tutorial. Ne deriva, quindi, che questa guida non funziona correttamente,<br />
in quanto l’applicazione non riesce a leggere i dati da Twitter. Sono già al lavoro<br />
<strong>per</strong> cercare di sistemare questo problema, s<strong>per</strong>o di poter aggiornare la guida in tempi brevi.<br />
Dopo aver creato un semplice lettore di feed RSS, complichiamo un po’ le cose. In questo capitolo<br />
realizzeremo un nostro <strong>per</strong>sonalissimo client <strong>per</strong> Twitter, uno dei social network di maggior<br />
successo dell’ultimo <strong>per</strong>iodo (io lo trovo molto utile).<br />
Nella realizzazione di questa applicazione vedremo vari aspetti diversi. Utilizzeremo, infatti,<br />
una classe che ho trovato su Internet: MGTwitterEngine (link del sito originale), che ci <strong>per</strong>metterà<br />
di interagire in maniera facile e veloce con Twitter. Analizzeremo, poi, altri due aspetti<br />
molto importanti: le UITableViewCe", ovvero le celle <strong>per</strong>sonalizzate <strong>per</strong> le UITableView e la<br />
classe NSUserDefault, che ci <strong>per</strong>metterà di salvare i dati della nostra applicazione.<br />
PARTE 1: CONNETTIAMOCI A TWITTER<br />
Nella prima parte del tutorial vedremo come connetterci a Twitter utilizzando la classe<br />
MGTwitterEngine che abbiamo già nominato più volte. Leggeremo, poi, tutta la nostra timeline<br />
e la salveremo all’interno di una struttura dati che creeremo appositamente.<br />
IMPOSTIAMO LA LIBRERIA “MGTWITTERENGINE”<br />
Iniziamo creando un nuovo progetto di tipo “View-based application” e chiamiamolo “SampleTwitterClient”.<br />
Prima di fare qualsiasi altra cosa, dobbiamo inserire la libreria MGTwitterEngine, che ci<br />
<strong>per</strong>metterà di interagire con Twitter. Scaricate l’ultima versione da questa repository SVN (trovate<br />
qui una mia guida su come fare), oppure scarica la versione 1.08 che vi mettiamo noi a disposizione<br />
(la trovate anche nei codici sorgenti forniti insieme a questo libro).<br />
Estraiamo l’archivio ed apriamo il file “MGTwitterEngine.xcodeproj”, un progetto esempio<br />
fornito dai creatori della classe, che potete guardare <strong>per</strong> avere una panoramica della libreria. La<br />
procedura da seguire è spiegata nel file “README.txt” di questo progetto, ma vi illustrerò tutti<br />
i passaggi in modo che non abbiate problemi di alcun genere.<br />
A noi interessa la cartella “MATwitterEngine” che trovate all’interno di “Classes”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 132
Prendetela e trascinatela all’interno del nostro progetto “SimpleTwitterClient” che abbiamo<br />
creato poco fa:<br />
e cliccate su “Add” nella schermata che vi apparirà appena rilascerete la cartella, ricordandovi di<br />
mettere il segno di spunta nell’opzione in alto.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 133
Possiamo chiudere il progetto “MGTwitterEngine” e tornare al nostro “SampleTwitterClient”.<br />
Importiamo, ora, il framework che si dovrà occupare del parsing XML. Clicchiamo con il tasto<br />
destro sulla cartella “Frameworks” e scegliamo “Add” -> “Existing Frameworks…”:<br />
Dall’elenco che appare selezioniamo poi “libxml2.dylib” e clicchiamo su “Add”.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 134
Abbiamo così importato il framework necessario.<br />
Ci manca solo un’o<strong>per</strong>azione <strong>per</strong> fare in modo che la libreria “MGTwitterEngine” funzioni alla<br />
<strong>per</strong>fezione. Facciamo doppio clic sul nome del progetto <strong>per</strong> aprirne le proprietà. Nella sezione<br />
“Build” cerchiamo la voce “Header Search Path”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 135
facciamo doppio clic su tale voce e quando si apre inseriamoci la stringa “$<strong>SDK</strong>ROOT/usr/include/libxml2ʺ″<br />
(ci basterà cliccare sul bottoncino “+”):<br />
Clicchiamo infine su “OK”. Abbiamo concluso la fase iniziale di creazione del nostro progetto.<br />
DEFINIAMO LA VISTA DI CARICAMENTO<br />
XCode ha già creato <strong>per</strong> noi una vista, “SampleTwitterClientViewController.xib”. Questa verrà<br />
caricata all’avvio dell’applicazione, sarà quindi qui che andremo a leggere la nostra timeline di<br />
Twitter. Prima di fare ciò, creiamo un semplice aspetto grafico <strong>per</strong> questa vista.<br />
Aprite il file “SampleTwitterClientViewController.xib” e modificatelo a vostro piacere. Io l’ho<br />
impostato così:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 136
L’unico componente di rilievo è il componente “UIActivityIndicatorView” posto sotto la label<br />
“Caricamento in corso...”, che utilizzeremo <strong>per</strong> far capire all’utente che l’applicazione sta caricando<br />
i dati e non è bloccata.<br />
Salvate il file e chiudete pure Interface Builder.<br />
CREIAMO LA CLASSE “TWEET”<br />
Come abbiamo già detto, la nostra applicazione andrà a leggere la timeline del nostro account<br />
di Twitter. Dobbiamo creare una classe, quindi, in grado di ospitare le informazioni di ogni singolo<br />
tweet letto. Per semplicità, ci limiteremo a salvare solo alcuni dati di ogni tweet: il nome<br />
dell’utente che ha “cinguettato”, la sua immagine del profilo e il testo del tweet.<br />
Facciamo clic con il tasto destro su “Classes” e clicchiamo poi su “Add” -> “New File…”. Creiamo<br />
poi una classe del tipo “Objective-C class”, e chiamiamola “Tweet”. Vediamo di definire le<br />
variabili e i metodi di questa classe.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 137
Nel file “Tweet.h” inseriamo il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
#import <br />
@interface Tweet : NSObject {<br />
! NSString *testo;<br />
! NSString *user;<br />
! UIImage *immagine;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSString *testo;<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSString *user;<br />
@pro<strong>per</strong>ty (nonatomic, retain) UIImage *immagine;<br />
@end<br />
Abbiamo dichiarato tre elementi, come vi ho anticipato poco fa:<br />
1. testo, che conterrà il messaggio del tweet, il testo appunto;<br />
2. user, che conterrà l’username di chi ha inserito il tweet letto;<br />
3. immagine, è l’immmagine (l’avatar) dell’utente che ha lasciato il tweet.<br />
Niente di complicato quindi. Nel file “Tweet.m” dovrete solo implementare il metodo “dealloc”<br />
e inserire “@synthesize”:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
#import "Tweet.h"<br />
@implementation Tweet<br />
@synthesize testo, user, immagine;<br />
-(void)dealloc{<br />
! [testo release];<br />
! [user release];<br />
! [immagine release];<br />
! [su<strong>per</strong> dealloc];<br />
}<br />
@end<br />
Ovviamente se intendete creare un client più complesso potrete aumentare i componenti di<br />
questa classe, oppure inserire dei metodi che eseguano qualche o<strong>per</strong>azione (ad esempio un controllo<br />
dei dati). Per questo tutorial, tuttavia, ci basteranno questi semplici elementi.<br />
DEFINIAMO LA CLASSE “SAMPLETWITTERCLIENTVIEWCON-<br />
TROLLER”<br />
È venuto finalmente il momento di implementare la classe che si occu<strong>per</strong>à di leggere la timeline<br />
di Twitter.<br />
Apriamo il file “SampleTwitterClientViewController.h” e inseriamo il seguente codice:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 138
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
#import <br />
#import "MGTwitterEngine.h"<br />
@class Tweet;<br />
@interface SampleTwitterClientViewController : UIViewController<br />
{<br />
! MGTwitterEngine *twitterEngine;<br />
! NSMutableArray *listaTweet;<br />
!<br />
! IBOutlet UIActivityIndicatorView *spinner;<br />
}<br />
-(NSString*)getMessaggio:(NSDictionary*)element;<br />
-(NSString*)getUser:(NSDictionary*)element;<br />
-(NSURL*)getUrlImage:(NSDictionary*)element;<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSMutableArray *listaTweet;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet UIActivityIndicatorView<br />
*spinner;<br />
@end<br />
Alla riga 7 abbiamo definito un elemento di tipo “MGTwitterEngine”, proprio quello della classe<br />
che abbiamo inserito all’inizio del tutorial. Sarà questo componente che si occu<strong>per</strong>à della<br />
connessione con Twitter e della lettura della nostra timeline. Nell’intestazione (riga 6) abbiamo<br />
anche inserito il protocollo di questa classe, che ci “obbliga” così ad implementare dei metodi<br />
che vedremo in seguito.<br />
L’array dichiarato alla riga 8 conterrà vari elementi del tipo “Tweet”, ognuno dei quali conterrà<br />
un tweet letto dal nostro account. Sarà, quindi, una lista che conterrà tutti i tweet della nostra<br />
timeline.<br />
La riga 10, invece, contiene la definizione della “spinning wheel”, ovvero la classica “rotella che<br />
gira”, l’UIActivityIndicatorView che abbiamo inserito in precedenza nella vista (e che collegheremo<br />
fra poco in IB).<br />
Ci sono poi 3 metodi getter (“getMessaggio”, “getUser” e “getUrlImage”) che avranno il compito<br />
di ricavare il campo desiderato, partendo dall’NSDictionary che ricevono in input, e di salvare<br />
le varie informazioni di ogni singolo tweet.<br />
Salviamo la classe e, prima di continuare l’implementazione, apriamo nuovamente il file<br />
“SampleTwitterClientViewController.xib”, in cui dovremo collegare l’elemento “UIActivityIndicatorView”<br />
che abbiamo appena definito con quello che abbiamo inserito in IB.<br />
Dal Pannello dei Documenti clicchiamo sul “File’s Owner” e andiamo poi nel “Connections<br />
Inspector”. Colleghiamo l’elemento “spinner” con il componente grafico “UIActivityIndicatorView”<br />
che abbiamo inserito in precedenza. Se abbiamo eseguito tutto correttamente avrete<br />
il seguente risultato:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 139
Possiamo salvare e chiudere Interface Builder<br />
LEGGIAMO LA TIMELINE<br />
Iniziamo ad implementare il codice che deve leggere i tweet dalla nostra timeline. Apriamo il<br />
file “SampleTwitterClientViewController.m” ed inseriamo il seguente codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
#import "SampleTwitterClientViewController.h"<br />
#import "Tweet.h"<br />
@implementation SampleTwitterClientViewController<br />
@synthesize listaTweet, spinner;<br />
-(void)viewDidLoad{<br />
!<br />
! // Username e password <strong>per</strong> accedere a Twitter<br />
NSString *username = @"user_name";<br />
NSString *password = @"password";<br />
// Create a TwitterEngine and set our login details.<br />
twitterEngine = [[MGTwitterEngine alloc] initWithDelegate:self];<br />
[twitterEngine setUsername:username password:password];<br />
// <strong>Get</strong> updates from people the authenticated user follows.<br />
[twitterEngine getFollowedTimelineFor:username since:nil<br />
startingAtPage:0];<br />
! !<br />
! [spinner startAnimating];<br />
}<br />
Non preoccupatevi troppo di capire il codice, in quanto l’ho preso direttamente dall’esempio<br />
fornito con la classe “MGTwitterEngine”. Ricordatevi, comunque, di inserire i vostro dati <strong>per</strong> il<br />
login alla riga 11 e 12. Le righe seguenti, invece, servono <strong>per</strong> inizializzare l’elemento “twitterEngine”,<br />
che si occu<strong>per</strong>à di leggere la timeline di Twitter.<br />
Alla riga 21, inoltre, abbiamo avviato la rotella (che fermeremo quando la procedura di lettura e<br />
conversione dei dati sarà terminata).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 140
Nota: se invece di leggere la vostra timeline vorreste leggere i messaggi di un utente (non la<br />
sua timeline, solo i suoi tweet) dovete sostituire l’istruzione alla riga 19 con la seguente:<br />
1 [twitterEngine getUserTimelineFor:username sinceID:nil<br />
startingAtPage:0 count:5];<br />
Inseriamo, ora, dei metodi obbligatori da inserire, in quanto parte del delegato “MGTwitterEngineDelegate”.<br />
Eccoli:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
- (void)requestSucceeded:(NSString *)requestIdentifier{<br />
NSLog(@"Request succeeded (%@)", requestIdentifier);<br />
}<br />
- (void)requestFailed:(NSString *)requestIdentifier<br />
withError:(NSError *)error{<br />
NSLog(@"Twitter request failed! (%@) Error: %@ (%@)", requestIdentifier,<br />
[error localizedDescription],<br />
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);<br />
! [spinner stopAnimating];<br />
! UIAlertView *alert = [[UIAlertView alloc]<br />
initWithTitle:@"Errore!"<br />
message:@"Connessione non riuscita.\nControlla i dati d'accesso"<br />
delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];<br />
! [alert show];<br />
! [alert release];<br />
}<br />
- (void)directMessagesReceived:(NSArray *)messages<br />
forRequest:(NSString *)identifier{<br />
NSLog(@"Got direct messages:\r%@", messages);<br />
}<br />
- (void)userInfoReceived:(NSArray *)userInfo forRequest:(NSString<br />
*)identifier{<br />
NSLog(@"Got user info:\r%@", userInfo);<br />
}<br />
- (void)miscInfoReceived:(NSArray *)miscInfo forRequest:(NSString<br />
*)identifier{<br />
! NSLog(@"Got misc info:\r%@", miscInfo);<br />
}<br />
L’unico metodo a cui ho aggiunto un po’ di codice è il secondo, ovvero “requestFailed: withError:”.<br />
Questo è richiamato se la connessione con Twitter non è possibile, quindi avviamo una<br />
UIAlertView che lo comunica all’utente e fermiamo la rotella. Come messaggio comunichiamo<br />
che i dati d’accesso sono errati, in realtà dovremmo controllare il codice d’errore e inserire un<br />
messaggio a seconda dell’errore riscontrato (potrebbe non essere presente la connessione, oppure<br />
Twitter potrebbe essere down, o i dati inseriti potrebbero essere errati, etc).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 141
Mancano solo pochi metodi <strong>per</strong> concludere questo primo tutorial. Ecco cosa dovete inserire<br />
ora:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
26<br />
27<br />
28<br />
29<br />
- (void)statusesReceived:(NSArray *)statuses forRequest:(NSString<br />
*)identifier{<br />
!<br />
! listaTweet = [[NSMutableArray alloc] init];<br />
! Tweet *elemento;<br />
!<br />
for (int i=0; i
molto semplice leggere le informazioni dei vari campi, vi basterà utilizzare il metodo “object-<br />
ForKey” e inserire l’attributo che volete leggere.<br />
Nota: il metodo “getUser” ci restituisce il nome completo dell’utente di cui abbiamo letto il<br />
messaggio. Se volete, invece, solo leggerne il nickname utilizzate questa istruzione (riga 23):<br />
1 return [[element objectForKey:@"user"] objectForKey:@"screen_name"];<br />
Quello che potrebbe sembrarvi più complicato è la lettura dell’immagine. Il metodo “getUrlImage”<br />
ci restituisce un elemento NSURL, che è l’indirizzo web dell’immagine dell’utente. Alla<br />
riga 10 creiamo, poi, un’immagine a partire dai dati letti a quell’indirizzo (XCode ci restituisce<br />
infatti un elemento NSData, che va convertito in UIImage). L’immagine convertita viene poi<br />
inserita nell’elemento corrente (ovviamente nel campo “immagine”).<br />
Alla fine del ciclo for avremo la “listaTweet” che conterrà n elementi di tipo Tweet, ognuno dei<br />
quali avrà le informazioni ricavate in precedenza. Proprio ciò che volevamo.<br />
Abbiamo così completato questa prima parte del tutorial!<br />
PARTE 2: CREIAMO LA TABELLA CON I TWEET LETTI<br />
In questa seconda parte vedremo come creare una tabella con le celle <strong>per</strong>sonalizzate, che dovrà<br />
visualizzare gli elementi Tweet che abbiamo salvato nella lista. Utilizzeremo, quindi, la classe<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 143
UITableViewCell <strong>per</strong> creare delle celle <strong>per</strong>sonalizzate, in modo da ottenere una tabella con<br />
un layout ad-hoc.<br />
Come prima cosa, andremo a creare la tabella che conterrà i tweet letti dalla nostra timeline.<br />
Iniziamo a creare, quindi, una tabella e la classe <strong>per</strong> gestirla.<br />
Andiamo “File” -> “New File…” e dalla sezione “Cocoa Touch Class” scegliamo “UIViewController<br />
subclass”, mettendo la spunta sulle opzioni “UITableViewController subclass” e “With<br />
XIB for user interface”.<br />
Facendo così avremo già un file “.xib” contenente una tabella e la classe associata, risparmiando<br />
tempo e lavoro.<br />
Se abbiamo creato tutto in modo corretto avremo i seguenti file nel nostro progetto (io li ho<br />
spostati <strong>per</strong> avere tutto ordinato):<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 144
Apriamo il file “tabellaTwitterViewController.xib”, dovremo fare una piccola modifica. Dal<br />
Pannello dei Documenti selezioniamo la “Table View” (ovvero la tabella) e apriamo poi il “Size<br />
Inspector”. Modifichiamo l’altezza delle celle, portando il valore a 70. Il campo da modificare è<br />
il seguente:<br />
Ovviamente potete dimensionare le celle a vostro piacimento, io ho ritenuto questa dimensione<br />
accettabile <strong>per</strong> la struttura che avevo in mente.<br />
Abbiamo così concluso la definizione grafica della tabella. Possiamo salvare e chiudere Interface<br />
Builder.<br />
CREIAMO LA CELLA PERSONALIZZATA<br />
Vediamo, ora, un’aspetto nuovo. Solitamente quando utilizziamo le tabelle ci limitiamo ad inserire<br />
del testo che sarà contenuto all’interno della cella. Per questo tutorial, invece, andremo a<br />
creare una nostra cella <strong>per</strong>sonalizzata, che comporrà poi la tabella.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 145
Il procedimento non è difficile, <strong>per</strong>ò merita attenzione <strong>per</strong> non <strong>per</strong>dere nessun passaggio. Iniziamo<br />
creando un file xib vuoto (“File” -> “New File…” -> “Empty XIB”) e chiamiamolo “cellaTweet”.<br />
Facciamo doppio clic sul file appena creato <strong>per</strong> aprirlo in IB.<br />
Inseriamo all’interno della vista un componente di tipo “UITableViewCell”:<br />
Facciamo doppio clic sul componente che abbiamo appena inserito, si aprirà questa piccola vista:<br />
Questa è la base della nostra cella <strong>per</strong>sonalizzata. Fra poco inseriremo i componenti che conterranno<br />
poi le informazioni che desideriamo (che saranno, ovviamente, quelle che abbiamo<br />
fatto salvare nella prima parte del tutorial, quindi nome utente, testo del tweet e immagine dell’utente).<br />
Prima di fare ciò, andiamo nel “Size Inspector” e modifichiamo l’altezza a 70 (lo stesso<br />
valore che abbiamo impostato prima nella tabella, ricordate?):<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 146
Andiamo, poi, nell’”Attributes Inspector” e nel campo “Identifier” inseriamo “Cell”:<br />
Ora inseriamo gli elementi che dovranno comporre tutte le singole celle. Ci serviranno due<br />
UILabel e una UIImageView. Io le ho disposte e <strong>per</strong>sonalizzate come vedete di seguito, voi siete<br />
liberissimi di inserirle in maniera diversa!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 147
Manca solo una piccola o<strong>per</strong>azione. Dobbiamo dare ai componenti un identificatore univoco,<br />
in modo che potremo, poi, selezionarli via codice in maniera molto veloce. Selezioniamo la<br />
UIImageView e andiamo nell’”Attributes Inspector”. Nel campo tag inseriamo il valore 0 (dovrebbe<br />
già essere presente):<br />
Facciamo la stessa o<strong>per</strong>azione con le due label, impostando <strong>per</strong> la label del nome utente il tag 1,<br />
mentre <strong>per</strong> la label che conterrà il testo del tweet il tag 2. Questa seconda label conterrà il testo<br />
dei tweet, quindi dobbiamo fare in modo che possa contenere più testo. Riduciamo le dimensioni<br />
del font e impostiamo il numero massimo di righe a 2:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 148
Abbiamo così concluso anche la definizione della cella <strong>per</strong>sonalizzata. Come vedete questo metodo<br />
è molto versatile, potrete <strong>per</strong>sonalizzare al massimo qualsiasi tabella!<br />
DEFINIAMO LA CLASSE DELLA TABELLA<br />
Dobbiamo ora iniziare a mettere mano al codice. Per prima cosa definiamo la tabella che mostrerà<br />
i tweet che abbiamo letto durante il caricamento dell’applicazione.<br />
Ecco il codice da inserire nel file “TabellaTwitterViewController.h”:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
#import <br />
@interface TabellaTwitterViewController : UITableViewController {<br />
! NSMutableArray *lista;<br />
! UITableViewCell *cellaNib;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSMutableArray *lista;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet UITableViewCell *cellaNib;<br />
- (UIImage *)scale:(UIImage *)image toSize:(CGSize)size;<br />
@end<br />
Come vedete il codice rispecchia quello che solitamente è utilizzato <strong>per</strong> la gestione delle tabelle.<br />
Abbiamo definito una lista di elementi (alla riga 4), che corrisponderà a quella che abbiamo<br />
definito nella classe “SampleTwitterClientViewController”. L’elemento “cellaNib”, invece, cor-<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 149
isponderà alla cella che abbiamo creato poco fa in Interface Builder.<br />
Alla riga 11, infine, troviamo la definizione di un metodo “scale”, che ci <strong>per</strong>metterà di ridimensionare<br />
l’immagine <strong>per</strong> essere contenuta interamente nella UIImageView della cella <strong>per</strong>sonalizzata.<br />
Questo ci <strong>per</strong>metterà di non sprecare memoria inutilmente.<br />
Definiamo, ora, il contenuto del file “TabellaTwitterViewController.m”. Iniziamo inserendo le<br />
seguenti intestazioni:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
#import "TabellaTwitterViewController.h"<br />
#import "Tweet.h"<br />
@implementation TabellaTwitterViewController<br />
@synthesize lista, cellaNib;<br />
Modifichiamo, poi, il metodo “tableView: numberOfRowInSection:” impostando come valore<br />
di ritorno la dimensione della lista:<br />
1<br />
2<br />
3<br />
- (NSInteger)tableView:(UITableView *)tableView<br />
numberOfRowsInSection:(NSInteger)section {<br />
return [lista count];<br />
}<br />
Ora dobbiamo implementare il metodo “tableView: cellForRowAtIndexPath:”. È un po’ diverso<br />
dal solito, eccovelo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
- (UITableViewCell *)tableView:(UITableView *)tableView<br />
cellForRowAtIndexPath:(NSIndexPath *)indexPath {<br />
static NSString *CellIdentifier = @"Cell";<br />
UITableViewCell *cell = [tableView<br />
dequeueReusableCellWithIdentifier:CellIdentifier];<br />
if (cell == nil) {<br />
! ! [[NSBundle mainBundle] loadNibNamed:@"cellaTweet"<br />
owner:self options:NULL];<br />
! ! cell = cellaNib;<br />
}<br />
!<br />
! Tweet *elemento = [lista objectAtIndex:indexPath.row];<br />
! UILabel *testoLabel = (UILabel*)[cell viewWithTag:2];<br />
! testoLabel.text = elemento.testo;<br />
! UILabel *userLabel = (UILabel*)[cell viewWithTag:1];<br />
! userLabel.text = elemento.user;<br />
!<br />
! UIImageView *immagine = (UIImageView*)[cell viewWithTag:3];<br />
! [immagine setImage:[self scale:elemento.immagine<br />
toSize:CGSizeMake(60, 60)]];<br />
!<br />
! return cell;<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 150
Come potete vedere, l’inizializzazione della cella avviene in maniera diversa dal solito. Alla riga<br />
7, infatti, viene creata una nuova cella partendo dal file xib “cellaTweet”. Nelle istruzioni successive<br />
vengono invece settate le varie informazioni del tweet (nome utente, testo e immagine).<br />
Potete vedere che l’elemento della cella viene richiamato mediante il tag (con la funzione [cell<br />
viewWithTag:X]), ecco <strong>per</strong>chè prima lo abbiamo impostato in Interface Builder.<br />
L’imagine, inoltre, viene ridimensionata con la funzione “scale: toSize:”. Importante sono i valori<br />
che vengono passati nell’oggetto CGMakeSize (riga 18): essi sono le dimensioni a cui vogliamo<br />
ridimensionare le nostre immagini (devono corrispondere con le dimensioni che avete impostato<br />
alla UIImageView nella cella <strong>per</strong>sonalizzata).<br />
Ecco, quindi, la definizione del metodo che ridimensiona le immagini:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
- (UIImage *)scale:(UIImage *)image toSize:(CGSize)size{<br />
UIGraphicsBeginImageContext(size);<br />
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];<br />
UIImage *scaledImage =<br />
UIGraphics<strong>Get</strong>ImageFromCurrentImageContext();<br />
UIGraphicsEndImageContext();<br />
return scaledImage;<br />
}<br />
Non commento questo metodo, in quanto l’ho trovato anche io su Internet, <strong>per</strong> la precisione a<br />
questo indirizzo. Ringrazio, quindi, il legittimo autore.<br />
La nostra tabella è completa!<br />
COMPLETIAMO L’APPLICAZIONE<br />
Ci mancano solo due cose <strong>per</strong> completare il nostro client.<br />
Per prima cosa, apriamo nuovamente il file “cellaTweet.xib”. Selezioniamo il “File’s Owner” ed<br />
entriamo nell’”Identity Inspector”. Impostiamo come classe della vista “TabellaTwitterView-<br />
Controller”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 151
Spostiamoci, poi, nel pannello “Connections Inspector” e colleghiamo l’elemento “cellaNib” al<br />
componente UITableViewCell che avevamo in precedenza inserito. Se avete fatto in maniera<br />
corretta il collegamento avrete il seguente risultato:<br />
Salviamo e chiudiamo pure Interface Builder.<br />
Dobbiamo ora solo completare il caricamento dell’applicazione, che deve avviare la tabella dopo<br />
aver letto la nostra timeline. Torniamo, quindi, in “SampleTwitterClientViewController.h”.<br />
Dobbiamo definire un elemento “TabellaTwitterViewController”, in modo da poterlo richiamare<br />
alla fine del caricamento dei tweet, facendo così apparire la nostra tabella. Modifichiamo<br />
così il file “SampleTwitterClientViewController.h”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 152
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
#import <br />
#import "MGTwitterEngine.h"<br />
@class Tweet;<br />
@class TabellaTwitterViewController;<br />
@interface SampleTwitterClientViewController : UIViewController<br />
{<br />
! MGTwitterEngine *twitterEngine;<br />
! NSMutableArray *listaTweet;<br />
!<br />
! IBOutlet UIActivityIndicatorView *spinner;<br />
!<br />
! TabellaTwitterViewController *tabellaTwitterViewController;<br />
}<br />
-(NSString*)getMessaggio:(NSDictionary*)element;<br />
-(NSString*)getUser:(NSDictionary*)element;<br />
-(NSURL*)getUrlImage:(NSDictionary*)element;<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSMutableArray *listaTweet;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet UIActivityIndicatorView<br />
*spinner;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet TabellaTwitterViewController<br />
*tabellaTwitterViewController;<br />
@end<br />
Andiamo, poi, nel file “SampleTwitterClientViewController.m”. Modifichiamo le dichiarazioni<br />
e le importazioni nel seguente modo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
#import "SampleTwitterClientViewController.h"<br />
#import "Tweet.h"<br />
#import "TabellaTwitterViewController.h"<br />
@implementation SampleTwitterClientViewController<br />
@synthesize listaTweet, spinner, tabellaTwitterViewController;<br />
Modifichiamo, ora, il metodo “statusesReceived: forRequest:”, inserendo il seguente codice alla<br />
fine di tale metodo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
[elemento release];<br />
!<br />
self.tabellaTwitterViewController.lista = self.listaTweet;<br />
!<br />
[spinner stopAnimating];<br />
!<br />
[self presentModalViewController:self.tabellaTwitterViewController<br />
animated:YES];<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 153
Con queste poche righe abbiamo semplicemente impostato la lista degli elementi della nostra<br />
tabella, che corrisponderà alla lista dei tweet che abbiamo creato in precedenza (parte 1 del tutorial).<br />
Abbiamo quasi terminato! Dobbiamo impostare la gestione di più viste proprio come abbiamo<br />
visto nel capitolo 10. Salviamo tutte le classi che abbiamo appena modificato e apriamo il file<br />
“SampleTwitterClientViewController.xib”. Inseriamo un elemento “UIViewController”:<br />
Selezioniamo poi tale elemento e in “Identity Inspector” selezioniamo come classe “TabellaTwitterViewController”.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 154
Nell’”Attributes Inspector” selezioniamo il file xib che deve essere associato a questa vista, ovvero<br />
“tabellaTwitterViewController”:<br />
Spostiamoci, infine, nel “File’s Owner” e colleghiamo l’elemento “tabellaTwitterViewController”<br />
con l’elemento UIViewController appena inserito. Ecco come deve presentarsi il pannello<br />
dopo il collegamento:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 155
Abbiamo concluso! Salviamo tutto, chiudiamo Interface Builder, clicchiamo su “Build and Go!”<br />
e testiamo il nostro <strong>per</strong>sonalissimo client di Twitter!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 156
PARTE 3: IL SALVATAGGIO DEI DATI<br />
In questa terza e ultima parte vedremo come utilizzare la classe NSUserDefault, che ci <strong>per</strong>mette<br />
di salvare delle informazioni relative alla nostra applicazione. Quello che andremo a salvare<br />
sarà la data in cui è stato eseguito l’ultimo refresh della timeline, che mostreremo all’avvio<br />
all’utente.<br />
Ovviamente questa è una semplificazione, in applicazioni più complesse potremmo avere molte<br />
più informazioni da memorizzare (ad esempio dei settaggi come l’autorefresh, il nome utente o<br />
la password). Analizzeremo, quindi, solo il salvataggio di un parametro, ma vedrete che non sarà<br />
nulla di difficile!<br />
La prima cosa da fare è inserire una label in cui venga visualizzata l’ultima data in cui è stato<br />
eseguito un refresh della nostra timeline.<br />
Nel file “SampleTwitterClientViewController.h” inseriamo la seguente dichiarazione (righe 12 e<br />
24):<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
26<br />
#import <br />
#import "MGTwitterEngine.h"<br />
@class Tweet;<br />
@class TabellaTwitterViewController;<br />
@interface SampleTwitterClientViewController : UIViewController<br />
{<br />
! MGTwitterEngine *twitterEngine;<br />
! NSMutableArray *listaTweet;<br />
!<br />
! IBOutlet UIActivityIndicatorView *spinner;<br />
! IBOutlet UILabel *labelUltimoRefresh;<br />
!<br />
! TabellaTwitterViewController *tabellaTwitterViewController;<br />
}<br />
-(NSString*)getMessaggio:(NSDictionary*)element;<br />
-(NSString*)getUser:(NSDictionary*)element;<br />
-(NSURL*)getUrlImage:(NSDictionary*)element;<br />
@pro<strong>per</strong>ty (nonatomic, retain) NSMutableArray *listaTweet;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet UIActivityIndicatorView<br />
*spinner;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet TabellaTwitterViewController<br />
*tabellaTwitterViewController;<br />
@pro<strong>per</strong>ty (nonatomic, retain) IBOutlet UILabel *labelUltimoRefresh;<br />
@end<br />
Salviamo il file e apriamo poi “SampleTwitterClientViewController.xib”, che aprirà IB. Inserite<br />
una o due label (a vostro piacere), io ho fatto così:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 157
La seconda label (quella che contiene il testo “Label”) sarà quella che visualizzerà la data dell’ultimo<br />
refresh della timeline. Selezionate il “File’s Owner” e collegate l’elemento “labelUltimo-<br />
Refresh”, che abbiamo appena definito, con la label in questione. Se avete eseguito il collegamento<br />
in maniera corretta avrete il seguente risultato:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 158
Abbiamo così completato questo step. Possiamo salvare tutto e chiudere Interface Builder.<br />
GESTIAMO IL CARICAMENTO / SALVATAGGIO DEI DATI<br />
Ora possiamo occuparci del codice che ci interessa, che andrà inserito nel file<br />
“SimpleTwitterClientViewController.m”.<br />
Prima di fare qualsiasi cosa, ricordiamoci di importare la pro<strong>per</strong>ty definita in precedenza, tramite<br />
la seguente istruzione (dovete solo aggiungere “labelUltimoRefresh”, le altre le avete già<br />
definite):<br />
1 @synthesize listaTweet, spinner, tabellaTwitterViewController, labelUltimoRefresh;<br />
Possiamo passare alla parte più importante. Vediamo, quindi, come salvare i valori che ci interessano.<br />
Come abbiamo già detto, dobbiamo salvare la data dell’ultimo refresh che l’applicazione<br />
ha eseguito.<br />
Il punto migliore <strong>per</strong> eseguire il salvataggio è dopo la creazione della lista con i vari tweet, che<br />
avviene nel metodo “statusesReceived: forRequest:”. Ecco, quindi, il codice da inserire in tale<br />
metodo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
[spinner stopAnimating];<br />
!<br />
NSDate *dataCorrente = [NSDate date];<br />
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];<br />
[defaults setObject:dataCorrente forKey:@"data"];<br />
[defaults synchronize];<br />
!<br />
[self presentModalViewController:self.tabellaTwitterViewController<br />
animated:YES];<br />
Nel istruzioni alle righe 1 e 8 le trovete già (le abbiamo inserite nei precedenti tutorial), dovete<br />
solo inserire le restanti. Alla riga 3 abbiamo istanziato un elemento di tipo NSDate, richiamando<br />
poi il metodo “date”, che ci restituisce la data e l’ora corrente. Abbiamo ottenuto, quindi, la<br />
data dell’ultimo refresh.<br />
Alla riga 4 e 5 eseguiamo il salvataggio vero e proprio: prima viene istanziato un oggetto di tipo<br />
NSUserDefault, poi si salvano al suo interno i valori desiderati. Ci sono vari metodi che devono<br />
essere utilizzati <strong>per</strong> salvare le variabili, a seconda del loro tipo. Nel nostro caso abbiamo utilizzato<br />
“setObject”, in quanto NSDate è un oggetto generico. Eccovi altri esempi di metodo <strong>per</strong> il<br />
salvataggio di variabili:<br />
1. [defaults setInteger:5 forKey:@"numeroIntero"];<br />
2. [defaults setBool:YES forKey:@"valoreBooleano"];<br />
3. [defaults setFloat:0.24 forKey:@"numeroFloat"];<br />
Come potete notare ci sono vari metodi, a seconda del tipo di variabile. Li trovate tutti, comunque,<br />
nella documentazione.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 159
L’ultima istruzione è alla riga 6, ovvero la chiamata del metodo “synchronize”. Non fateci troppo<br />
caso, inseritela. Chi di voi svilup<strong>per</strong>à applicazioni con multithread o accesso a risorse condivise<br />
dovrà sviluppare questo aspetto, <strong>per</strong> gli altri non è nulla di importante.<br />
Ora non ci resta che inserire il codice che deve occuparsi della lettura del valore salvato. Tale<br />
lettura va eseguita, ovviamente, all’avvio dell’applicazione. Nel metodo “viewDidLoad”, quindi,<br />
aggiungiamo il codice seguente (dalla riga 14 alla 19):<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
-(void)viewDidLoad{<br />
!<br />
! // Username e password <strong>per</strong> accedere a Twitter<br />
NSString *username = @"user_name";<br />
NSString *password = @"password";<br />
// Create a TwitterEngine and set our login details.<br />
twitterEngine = [[MGTwitterEngine alloc] initWithDelegate:self];<br />
[twitterEngine setUsername:username password:password];<br />
// <strong>Get</strong> updates from people the authenticated user follows.<br />
[twitterEngine getFollowedTimelineFor:username since:nil<br />
startingAtPage:0];<br />
!<br />
! NSDate *dataUltimoAgg = [[NSUserDefaults standardUserDefaults]<br />
objectForKey:@"data"];<br />
! if (dataUltimoAgg == nil) {<br />
! ! labelUltimoRefresh.text = @"nessun refresh precedente";<br />
! }else{<br />
! ! labelUltimoRefresh.text = [[NSString alloc]<br />
initWithFormat:@"%@",dataUltimoAgg];<br />
! }<br />
!<br />
! [spinner startAnimating];<br />
}<br />
Come potete vedere, abbiamo definito un oggetto di tipo NSDate, che dovrà contenere il valore<br />
della data che leggeremo dai salvataggi. Per leggere tale valore, utilizziamo un metodo appropriato,<br />
nel nostro caso è “objectForKey”. Se, invece, avessimo dovuto leggere un numero<br />
intero avremmo utilizzato il metodo “integerForKey”. Sono speculari, insomma, a quelli visti<br />
<strong>per</strong> il salvataggio dei dati. Nella documentazione, comunque, trovate tutti i metodi disponibili.<br />
Abbiamo poi eseguito un controllo su tale valore: nel caso l’oggetto sia nullo (quindi non è stato<br />
letto niente), vuol dire che l’applicazione è avviata <strong>per</strong> la prima volta, quindi scriviamo un<br />
testo appropriato. In caso contrario, inseriamo nella label la data letta.<br />
Abbiamo concluso anche il salvataggio dei dati!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 160
Ecco il vostro client di Twitter completato e funzionante!!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 161
Capitolo 16: Realizziamo il nostro “Brushes”<br />
Quello che ho pensato <strong>per</strong> voi questa volta è un po’ particolare, ma secondo me molto carino e<br />
con molte cose utili. Sicuramente tutti voi conoscerete Brushes (link iTunes), un programma<br />
molto famoso <strong>per</strong> disegnare sul proprio <strong>iPhone</strong> e iPod Touch.<br />
Ho pensato, quindi, di spiegarvi come realizzarne uno tutto vostro! Realizzeremo una vista che<br />
conterrà la “tavola grafica”, ovvero la parte in cui l’utente potrà diegnare. Ci sarà, poi, una seconda<br />
vista in cui inseriremo le impostazioni, <strong>per</strong> <strong>per</strong>mettere all’utente di cambiare il colore e<br />
la dimensione del pennello. Vedremo, infine, come fare in modo che l’utente possa salvare i<br />
propri disegni nell’Album foto dell’<strong>iPhone</strong>.<br />
PARTE 1: CREIAMO LA TAVOLA GRAFICA<br />
In questa prima parte vedremo come fare in modo che l’utente possa, muovendo il dito sullo<br />
schermo, disegnare a suo piacimento. Per questa applicazione sfrutteremo il template “Utility<br />
Application”, che ci <strong>per</strong>mette di avere già due viste, in modo da risparmiare un po’ di lavoro.<br />
CREIAMO UN NUOVO PROGETTO<br />
Iniziamo creando il progetto <strong>per</strong> la nostra applicazione. Create un nuovo progetto di tipo “Utility<br />
Application” e inserite “SampleBrushes” come nome.<br />
La struttura che abbiamo selezionato ci mette a disposizione due viste: una “Main View” che è<br />
quella che appare inizialmente, e una “Flipside View”, che appare se viene premuto il pulsante<br />
“i” (info), con un’animazione già definita. Queste due viste, quindi, potremo sfruttarle <strong>per</strong> creare<br />
la nostra applicazione: nella “Main View” creeremo la zona in cui l’utente potrà disegnare,<br />
mentre nella “Flipside View” inseriremo le impostazioni (quindi il colore del pennello, la dimensione,<br />
etc).<br />
Prima di definire l’aspetto grafico della nostra applicazione, definiamo un componente che poi<br />
andremo a collegare con un elemento in Interface Builder.<br />
Aprite, quindi, il file “MainViewController.h” (nella sottocartella “Main View”) e inserite le seguenti<br />
definizioni:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
#import "FlipsideViewController.h"<br />
@interface MainViewController : UIViewController <br />
{<br />
! IBOutlet UIImageView *viewDisegno;<br />
!<br />
}<br />
- (IBAction)showInfo;<br />
- (IBAction)cancella;<br />
@end<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 162
Alla riga 4 abbiamo definito un oggetto di tipo UIImageView, che sarà l’oggetto in cui l’utente<br />
disegnerà, e che visualizzerà, quindi, una serie di componenti grafiche colorate. Alla riga 9, invece,<br />
abbiamo definito un’azione, che ci servirà <strong>per</strong> cancellare tutto ciò che l’utente ha disegnato.<br />
DEFINIAMO L’ASPETTO GRAFICO DELL’APPLICAZIONE<br />
Salviamo il file e apriamo “MainView.xib”. Ci ritroveremo con una vista come questa:<br />
Dobbiamo modificarne un po’ l’aspetto. Iniziamo scegliendo come colore di sfondo il bianco<br />
(lo fate semplicemente dal pannello Attributes Inspector). Cancellate, inoltre, il bottone “i” che<br />
è presente nell’angolo basso destro della vista.<br />
Inserite, quindi, un componente di tipo “UIImageView”, in modo che occupi tutta la vista:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 163
Aggiungete, poi, una UIToolbar sul fondo della vista stessa. Io ho messo come stile della toolbar<br />
“Black Translucent”, ovviamente voi potete farla come preferite. Inserite, inoltre, due bottoni<br />
“Bar Button Item”, e un “Flexible Space Bar Button Item” tra i due. Il primo bottone rinominatelo<br />
in “Cancella” mentre il secondo in “Settings” (Impostazioni è troppo lunga come<br />
dicitura xD). Ecco l’aspetto finale della mia applicazione:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 164
Ovviamente sarebbe più carino inserire delle immagini nei bottoni, ma <strong>per</strong> semplicità ho inserito<br />
dei semplici nomi.<br />
Colleghiamo, ora, l’elemento e le azioni che abbiamo definito poco fa via codice (l’azione<br />
“showInfo” era già presente di default). Dal pannello dei documenti selezioniamo “File’s Owner”<br />
e spostiamoci in “Connections Inspector”. Colleghiamo “viewDisegno” con la UIImage-<br />
View che abbiamo inserito, l’azione “cancella” colleghiamola con l’omonimo pulsante, mentre<br />
“showInfo” collegatela con il bottone “Settings”. Se avrete eseguito tutto correttamente avrete<br />
un pannello delle connessioni come questo:<br />
Abbiamo concluso questa fase. Possiamo salvare il tutto e chiudere Interface Builder.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 165
DEFINIAMO I METODI NECESSARI<br />
Torniamo ora al file “MainViewController.h”. Dobbiamo definire degli elementi che ci serviranno<br />
nel nostro programma. Ecco il codice da aggiungere a quello già presente:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
#import "FlipsideViewController.h"<br />
@interface MainViewController : UIViewController <br />
{<br />
! IBOutlet UIImageView *viewDisegno;<br />
!<br />
! CGPoint ultimoPunto;<br />
!<br />
! float dimensionePennello;<br />
! UIColor *colorePennello;<br />
}<br />
- (IBAction)showInfo;<br />
- (IBAction)cancella;<br />
@end<br />
Analizziamo gli elementi che abbiamo appena inserito. Alla riga 6 abbiamo definito un oggetto<br />
CGPoint, che non è altro che un contenitore delle due componenti di un punto: le coordinate<br />
x e y. Questo ci servirà <strong>per</strong> sa<strong>per</strong>e il punto precedente a quello considerato, <strong>per</strong>mettendoci così<br />
di tracciare una linea. Alla riga 8 e 9 definiamo le caratteristiche del pennello: dimensione e colore.<br />
La dimensione è una variabile di tipo reale (float), mentre il colore è definito dal tipo UI-<br />
Color, che inizializzeremo con lo standard RGB.<br />
Queste sono le uniche dichiarazioni di cui abbiamo bisogno. Salviamo quindi questo file e spostiamoci<br />
in “MainViewController.m”.<br />
Le azioni che ci interessa definire saranno da implementare in 3 metodi tipici della gestione del<br />
multitouch:<br />
1. touchesBegan, richiamato quando si inizia un movimento. Dovremo ricavare il punto in cui<br />
deve iniziare il disegno;<br />
2. touchesMoved, richiamato quando un movimento è in corso. Ogni volta che viene avviato<br />
deve disegnare un segmento colorato, in modo che appaia una linea raffigurante il disegno<br />
dell’utente;<br />
3. touchesEnded, metodo richiamato quando il movimento è terminato. In particolare serve<br />
quando l’utente compie solo un singolo tap, disegnando così un semplice punto.<br />
Iniziamo, quindi, a scrivere il codice necessario. Iniziamo con il metodo “viewDidLoad”:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 166
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
- (void)viewDidLoad {<br />
[su<strong>per</strong> viewDidLoad];<br />
!<br />
! dimensionePennello = 5.0;<br />
! colorePennello = [[UIColor colorWithRed:1.0 green:0.0 blue:0.0<br />
alpha:1.0] retain];<br />
}<br />
Il suo compito è molto semplice e chiaro: viene impostata una dimensione standard del pennello,<br />
a 5.0 (pixel) e un colore, in questo caso il rosso. La definizione del colore avviene settando le<br />
componenti RGB, ovvero Red (rosso), Green (verde) e Blue (blu): variando le quantità con un<br />
valore compreso da 0.0 a 1.0 otterremo tutti i colori ammessi da questo sistema. Il campo alpha,<br />
invece, rappresenta la trasparenza. Fate qualche prova <strong>per</strong> prendere confidenza con questo<br />
sistema!<br />
Il secondo metodo che andiamo a definire è “touchesBegan”. La sua implementazione è molto<br />
semplice, dobbiamo solo ricavare il punto di inizio del movimento. Ecco il metodo da inserire:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {<br />
!<br />
! UITouch *touch = [touches anyObject];<br />
! ultimoPunto = [touch locationInView:viewDisegno];<br />
}<br />
Come vedete è molto semplice: dall’oggetto touch si ricava il punto (sempre definito come<br />
CGPoint), che viene assegnato all’oggetto “ultimoPunto” (riga 4). È importante specificare<br />
“viewDisegno” come parametro della funzione “locationInView”, altrimenti ricaverete tocchi<br />
relativi anche ad altre parti dello schermo, che <strong>per</strong>ò a noi non interessano.<br />
Passiamo ora alla definizione del metodo più impegnativo e importante: “touchesMoved”. Ecco<br />
il metodo da inserire:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 167
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {<br />
! UITouch *touch = [touches anyObject];!<br />
! CGPoint puntoCorrente = [touch locationInView:viewDisegno];<br />
!<br />
! // definiamo il contest grafico<br />
! UIGraphicsBeginImageContext(viewDisegno.frame.size);<br />
! [viewDisegno.image drawInRect:CGRectMake(0, 0,<br />
viewDisegno.frame.size.width, viewDisegno.frame.size.height)];<br />
! // settiamo la forma e la dimensione del pennello<br />
! CGContextSetLineCap(UIGraphics<strong>Get</strong>CurrentContext(), kCGLineCapRound);<br />
! CGContextSetLineWidth(UIGraphics<strong>Get</strong>CurrentContext(), dimensione-<br />
Pennello);<br />
! // convertiamo il colore e impostiamolo come colore del pennello<br />
! const CGFloat *components = CGColor<strong>Get</strong>Components([colorePennello<br />
CGColor]);<br />
! CGContextSetRGBStrokeColor(UIGraphics<strong>Get</strong>CurrentContext(), components[0],<br />
components[1], components[2], components[3]);<br />
! // disegna il <strong>per</strong>corso<br />
! CGContextBeginPath(UIGraphics<strong>Get</strong>CurrentContext());<br />
! CGContextMoveToPoint(UIGraphics<strong>Get</strong>CurrentContext(),<br />
ultimoPunto.x, ultimoPunto.y);<br />
! CGContextAddLineToPoint(UIGraphics<strong>Get</strong>CurrentContext(),<br />
puntoCorrente.x, puntoCorrente.y);<br />
! CGContextStrokePath(UIGraphics<strong>Get</strong>CurrentContext());<br />
! // settiamo il disegno appena creato<br />
! viewDisegno.image = UIGraphics<strong>Get</strong>ImageFromCurrentImageContext();<br />
! UIGraphicsEndImageContext();<br />
!<br />
! ultimoPunto = puntoCorrente;!<br />
}<br />
Iniziamo ad analizzare passo passo il codice che abbiamo appena scritto.<br />
Alla riga 7 troviamo la definizione di un “Graphics Contexts”. Questo è un aspetto complesso<br />
del Core Graphics, ma utilizzando questa funzione lo adattiamo semplicemente alla nostra<br />
UIImageView, che infatti gli passiamo come parametro. Questo ci <strong>per</strong>metterà di disegnare all’interno<br />
della nostra immagine. Con l’istruzione seguente, infatti, definiamo l’area in cui potremo<br />
disegnare: essa avrà la stessa dimensione dell’immagine “viewDisegno”.<br />
Le righe 10 e 11 si riferiscono alla definizione del “pennello”, con cui l’utente disegnerà sullo<br />
schermo. Prima, infatti, viene impostata la forma (in questo caso “kCGLineCapRound” è di<br />
forma circolare, ma possiamo anche farlo quadrato o triangolare, vi basta guardare la documentazione<br />
<strong>per</strong> vedere gli altri valori possibili), poi la dimensione, passando ovviamente la variabile<br />
“dimensionePennello”, che contiene proprio il valore desiderato (riga 11).<br />
Le righe 13 e 14 servono <strong>per</strong> impostare il colore al nostro pennello. Abbiamo visto prima che il<br />
colore è definito da un elemento UIColor. Purtroppo dobbiamo convertire le varie componenti<br />
in CGFloat, e l’unico modo che ho trovato è quello che vedete nel codice. Prima convertiamo<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 168
l’elemento “colorePennello” in un array di tipo CGFloat (riga 13), poi passiamo le varie componenti<br />
all’istruzione che setta il colore del pennello (riga 14).<br />
Le righe dalla 16 alla 19 sono quelle che si occupano del disegno vero e proprio della linea. Partendo<br />
da “ultimoPunto” fino a “puntoCorrente” viene disegnato un tratto, un disegno, che<br />
comporrà poi il tratto voluto dall’utente.<br />
Le righe 21 e 22 settano il disegno che è stato creato nell’immagine “viewDisegno”, rendendola<br />
così visibile all’utente.<br />
Come vedete non è poi così complicato il codice, <strong>per</strong>ò bisogna fare attenzione a non dimenticare<br />
niente.<br />
Manca poco <strong>per</strong> terminare il nostro programma! Dobbiamo definire il metodo “touchesEnded”.<br />
Esso dovrà esattamente fare le stesse cose che fa il metodo “touchesMoved”. Potremmo<br />
anche non implementare questo metodo, <strong>per</strong>ò in caso di singolo tap non succederebbe niente,<br />
mentre noi vogliamo disegnare un singolo punto. Ovviamente potete <strong>per</strong>sonalizzare questo<br />
aspetto, decidendo voi l’azione da compiere. Ecco il codice da inserire se volete che ad un singolo<br />
tap venga disegnato un punto:<br />
1<br />
2<br />
3<br />
4<br />
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {<br />
!<br />
! [self touchesMoved:touches withEvent:event];<br />
}<br />
Come vedete non facciamo altro che richiamare il metodo “touchesMoved”, davvero semplicissimo.<br />
L’ultima cosa da fare è l’implementazione del metodo “cancella”. Anche questo è davvero molto<br />
semplice, <strong>per</strong> cancellare tutto ciò che l’utente ha disegnato basta porre a “nil” l’immagine:<br />
1<br />
2<br />
3<br />
- (IBAction)cancella{<br />
! viewDisegno.image = nil;<br />
}<br />
Davvero semplice!<br />
Abbiamo concluso questa prima parte del nostro tutorial! Clicchiamo “Build and Run” e testiamo<br />
il nostro <strong>per</strong>sonalissimo Brushes!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 169
PARTE 2: INSERIAMO I SETTAGGI<br />
In questa seconda parte aggiungeremo alcuni aspetti fondamentali <strong>per</strong> migliorare l’applicazione:<br />
la possibilità di cambiare la dimensione e il colore del pennello, e la possibilità di salvare i<br />
disegni.<br />
Vedremo, quindi, come due classi diverse possano comunicare tra loro, e come utilizzare il metodo<br />
“imageSavedToPhotosAlbum” che <strong>per</strong>mette di salvare delle immagini nella galleria dell’utente.<br />
AGGIUNGIAMO LE IMPOSTAZIONI<br />
Iniziamo dichiarando nella classe “FlipsideViewController.h” gli elementi che poi andremo a<br />
definire in Interface Builder. Ecco il codice da inserire:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 170
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24<br />
25<br />
26<br />
27<br />
28<br />
@protocol FlipsideViewControllerDelegate;<br />
@interface FlipsideViewController : UIViewController {<br />
! id delegate;<br />
!<br />
! IBOutlet UISlider *sliderRosso, *sliderBlu, *sliderVerde, *sliderAlpha,<br />
*sliderDimensione;<br />
! IBOutlet UIImageView *viewColore;<br />
! IBOutlet UILabel *labelDimensione;<br />
!<br />
! UIColor *colorePennello;<br />
! float dimensionePennello;<br />
}<br />
@pro<strong>per</strong>ty (nonatomic, assign) id <br />
delegate;<br />
@pro<strong>per</strong>ty (nonatomic, assign) UIColor *colorePennello;<br />
@pro<strong>per</strong>ty (nonatomic, assign) float dimensionePennello;<br />
- (IBAction)done;<br />
- (IBAction)cambiaColore;<br />
- (IBAction)cambiaDimensione;<br />
@end<br />
@protocol FlipsideViewControllerDelegate<br />
- (void)flipsideViewControllerDidFinish:(FlipsideViewController<br />
*)controller nuovoColore:(UIColor*)colore<br />
nuovaDimensione:(float)dimensione;<br />
@end<br />
Parte di questo codice è già presente nella classe. Alle righe 7, 8, 9 abbiamo definito gli elementi<br />
grafici che ci serviranno. Come potete vedere, ci serviranno tre slider <strong>per</strong> cambiare il colore del<br />
pennello (più uno <strong>per</strong> la trasparenza, “alpha”), una UIImageView in cui mostreremo il colore<br />
corrente, in modo che l’utente possa vedere subito quale colore sta selezionando, uno slider e<br />
una label <strong>per</strong> la dimensione del pennello. Abbiamo, inoltre, definito due nuove azioni (righe 20<br />
e 21): esse verranno richiamate quando si muovono gli slider.<br />
Salviamo il file e apriamo “FlipsideView.xib”. Inserite i componenti necessari in modo da avere<br />
una struttura come la seguente:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 171
Dobbiamo eseguire i collegamenti con gli elementi che abbiamo definito in precedenza. Dal<br />
Pannello dei Documenti selezionate il “File’s Owner” e nel pannello “Connection Inspector”<br />
collegate i vari slider e la UIImageView (niente di difficile). Se avete eseguito questi collegamenti<br />
correttamente avrete un pannello come questo:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 172
Dobbiamo adesso collegare anche le due azioni. Collegate “cambiaColore” con tutti e quattro<br />
gli slider del colore, selezionando ogni volta “Value Changed” nel menù che vi appare. Collegate,<br />
infine, “cambiaDimensione” con lo slider della dimensione del pennello. Ecco come appare<br />
il vostro pannello con tutti i collegamenti effettuati:<br />
Abbiamo quasi concluso questa parte. Ci manca solo la definizione dei valori massimi e minimi<br />
dei vari slider. Selezioniamo il primo slider (quello <strong>per</strong> il rosso), spostiamoci nell’Attributes Inspector<br />
e controlliamo che come “Minumum Value” sia impostato 0.0, mentre come “Maximum<br />
Value” ci sia 1.0:<br />
Controllate anche i restanti slider dedicati al colore.<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 173
Per lo slider della dimensione, invece, dobbiamo impostare dei valori diversi. Io ho scelto 1.0<br />
come minimo, e 25.0 come massimo. Ovviamente potete variare come volete questi valori, magari<br />
effettuando delle prove.<br />
Abbiamo concluso la definizione grafica del pannello delle impostazioni. Salviamo il file e chiudiamo<br />
Interface Builder.<br />
SCRIVIAMO IL CODICE NECESSARIO<br />
Dobbiamo ora impostare il codice necessario. Apriamo il file “FlipsideViewController.m” e iniziamo<br />
ad inserire questo codice:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
#import "FlipsideViewController.h"<br />
@implementation FlipsideViewController<br />
@synthesize delegate, colorePennello, dimensionePennello;<br />
- (void)viewDidLoad {<br />
[su<strong>per</strong> viewDidLoad];<br />
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];<br />
!<br />
! const CGFloat *components = CGColor<strong>Get</strong>Components([colorePennello<br />
CGColor]);<br />
! [sliderRosso setValue:components[0]];<br />
! [sliderVerde setValue:components[1]];<br />
! [sliderBlu setValue:components[2]];<br />
! [sliderAlpha setValue:components[3]];<br />
! [viewColore setBackgroundColor:colorePennello];<br />
! labelDimensione.text = [NSString<br />
stringWithFormat:@"%f",dimensionePennello];<br />
! [sliderDimensione setValue:dimensionePennello];<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 174
Per prima cosa ricordatevi di inserire le @synthesize degli elementi “colorePennello” e “dimensionePennello”.<br />
Questi due valori li passeremo direttamente dalla “MainView”, quindi è importante<br />
che ci siano le due proprietà impostate correttamente. Passeremo i due valori in modo<br />
che all’a<strong>per</strong>tura del pannello <strong>per</strong> modificare il pennello l’utente trovi i valori correnti che sta<br />
utilizzando (quindi colore e dimensione attuali).<br />
Nel metodo “viewDidLoad” facciamo proprio quello che vi ho appena detto, ovvero inizializziamo<br />
i componenti grafici ai valori del pennello. All’avvio dell’applicazione tali valori saranno<br />
rosso <strong>per</strong> il colore, e 5.0 <strong>per</strong> la dimensione. Questi valori, <strong>per</strong>ò, potranno essere variati dall’utente,<br />
quindi è necessario che ogni volta che viene a<strong>per</strong>ta la vista delle impostazioni essi siano<br />
settati correttamente. In particolare, ricaviamo dal colore le varie componenti (come abbiamo<br />
già visto nella prima parte del tutorial), e settiamo il valore degli slider (righe 11-15). Alla<br />
riga 16 impostiamo il colore della UIImageView, che ci mostrerà così il colore del nostro pennello.<br />
Le ultime due righe, infine, servono <strong>per</strong> ricavare la dimensione del pennello e settare la<br />
label predisposta.<br />
Dobbiamo ora definire le due azioni collegate agli slider. Ecco i due metodi (davvero semplici)<br />
da implementare:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
- (IBAction)cambiaColore{<br />
! [viewColore setBackgroundColor:[UIColor<br />
colorWithRed:sliderRosso.value green:sliderVerde.value<br />
blue:sliderBlu.value alpha:sliderAlpha.value]];<br />
}<br />
- (IBAction)cambiaDimensione{<br />
! labelDimensione.text = [NSString<br />
stringWithFormat:@"%f",sliderDimensione.value];<br />
}<br />
Il primo metodo (“cambiaColore”) non fa altro che leggere i valori degli slider e settare lo sfondo<br />
dell’immagine con l’UIColor corrispondente. Il secondo metodo lavora nello stesso modo,<br />
solamente che visualizza il valore dello slider della dimensione del pennello. Semplici vero?<br />
Ci manca solo una modifica ad un metodo già esistente. Dobbiamo, infatti, passare alla classe<br />
“MainView” i nuovi valori della dimensione e del colore del pennello. Modifichiamo, quindi, il<br />
metodo “done” nel seguente modo:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
- (IBAction)done {<br />
! dimensionePennello = sliderDimensione.value;<br />
! colorePennello = [UIColor colorWithRed:sliderRosso.value<br />
green:sliderVerde.value blue:sliderBlu.value<br />
alpha:sliderAlpha.value];<br />
! [self.delegate flipsideViewControllerDidFinish:self<br />
nuovoColore:colorePennello nuovaDimensione:dimensionePennello];!<br />
}<br />
Abbiamo semplicemente letto il valore della dimensione e del colore del pennello, <strong>per</strong> poi passarlo<br />
al metodo “flipsideviewControllerDidFinish”, che abbiamo opportunamente modificato<br />
(infatti vedrete che ci sono dei nuovi parametri che gli vengono passati).<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 175
Torniamo al file “FlipsideViewController.h” e modifichiamo anche l’intestazione del metodo<br />
che troviamo nel fondo della classe:<br />
1<br />
2<br />
3<br />
@protocol FlipsideViewControllerDelegate<br />
- (void)flipsideViewControllerDidFinish:(FlipsideViewController<br />
*)controller nuovoColore:(UIColor*)colore<br />
nuovaDimensione:(float)dimensione;<br />
@end<br />
Abbiamo quasi terminato.<br />
Torniamo al file “MainViewController.m”, dobbiamo modificare due cose. Dobbiamo fare in<br />
modo che venga passato alla vista delle impostazioni i valori del pennello, e, viceversa, che vengano<br />
aggiornati dopo che l’utente li ha variati.<br />
Iniziate modificando il metodo “flipsideViewControllerDidFinish”, che trovate già nella vostra<br />
classe:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
- (void)flipsideViewControllerDidFinish:(FlipsideViewController<br />
*)controller nuovoColore:(UIColor*)colore<br />
nuovaDimensione:(float)dimensione{<br />
! const CGFloat *components = CGColor<strong>Get</strong>Components([colore CGColor]);<br />
! colorePennello = [[UIColor colorWithRed:components[0]<br />
green:components[1] blue:components[2] alpha:components[3]] retain];<br />
! dimensionePennello = dimensione;<br />
!<br />
! [self dismissModalViewControllerAnimated:YES];<br />
}<br />
Come potete vedere, è stata <strong>per</strong> prima cosa modificata l’intestazione del metodo (proprio quello<br />
che vi ho accennato poco fa). Vengono, poi, aggiornate le caratteristiche del pennello, inserendo<br />
il nuovo colore e la nuova dimensione.<br />
Il secondo metodo da modificare è “showInfo”, anch’esso già definito da XCode:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
- (IBAction)showInfo {<br />
!<br />
! FlipsideViewController *controller = [[FlipsideViewController<br />
alloc] initWithNibName:@"FlipsideView" bundle:nil];<br />
! controller.delegate = self;<br />
! controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;<br />
!<br />
! controller.dimensionePennello = dimensionePennello;<br />
! controller.colorePennello = colorePennello;<br />
!<br />
! [self presentModalViewController:controller animated:YES];<br />
!<br />
! [controller release];<br />
}<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 176
A questo metodo aggiungiamo solo le righe 6 e 7, in modo da passare alla vista delle impostazioni<br />
le proprietà correnti del nostro pennello (quelle che vengono lette nel metodo<br />
“viewDidLoad” che abbiamo scritto prima).<br />
Abbiamo concluso anche questa parte.<br />
INSERIAMO IL SALVATAGGIO DEL DISEGNO<br />
Vogliamo ora aggiungere una funzione molto importante: il salvataggio del disegno creato. Vogliamo<br />
<strong>per</strong>mettere all’utente, quindi, di salvare il suo disegno, in modo che possa poi ritrovarlo<br />
nel Rullino Fotografico.<br />
Iniziamo definendo in “MainViewController” un metodo che assoceremo ad un pulsante nella<br />
nostra applicazione. Ecco cosa dovete aggiungere nel file “MainViewController.h”:<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
#import "FlipsideViewController.h"<br />
@interface MainViewController : UIViewController <br />
{<br />
! IBOutlet UIImageView *viewDisegno;<br />
!<br />
! CGPoint ultimoPunto;<br />
!<br />
! float dimensionePennello;<br />
! UIColor *colorePennello;<br />
}<br />
- (IBAction)showInfo;<br />
- (IBAction)cancella;<br />
- (IBAction)salva;<br />
@end<br />
Come vedete abbiamo aggiunto solo la definizione del metodo “salva” alla riga 14.<br />
Salviamo il file e apriamo la vista “MainView.xib”. Nella toolbar inseriamo un bottone, dal “File’s<br />
Owner” colleghiamo l’azione salva a tale bottone. Se avrete eseguito tutto correttamente<br />
avrete i seguenti risultati:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 177
Salvate tutto e spostatevi nel file “MainViewController.m”.<br />
Dobbiamo ora definire il metodo salva, scrivendo il codice necessario <strong>per</strong> salvare l’immagine<br />
nella galleria dell’utente. Ecco il codice da inserire:<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 178
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
- (IBAction) salva{<br />
! UIImageWriteToSavedPhotosAlbum(viewDisegno.image, self, @selector(imageSavedToPhotosAlbum:<br />
didFinishSavingWithError: contextInfo:),<br />
nil);<br />
}<br />
- (void)imageSavedToPhotosAlbum:(UIImage *)image<br />
didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo<br />
{<br />
NSString *messaggio;<br />
NSString *titolo;<br />
if (!error) {<br />
! ! titolo = @"Salvataggio";<br />
messaggio = @"Immagine salvata con successo";<br />
! } else {<br />
titolo = @"Errore";<br />
! ! messaggio = [error description];<br />
! }<br />
! UIAlertView *alert = [[UIAlertView alloc] initWithTitle:titolo<br />
message:messaggio delegate:nil cancelButtonTitle:@"OK"<br />
otherButtonTitles:nil];<br />
! [alert show];<br />
! [alert release];<br />
}<br />
Come potete vedere il codice è molto semplice. Il metodo salva non fa altro che richiamare un<br />
metodo “imageSavedToPhotosAlbum”, che si occupa di salvare l’immagine nella galleria. In tale<br />
metodo, infatti, non vedrete istruzioni che si occupano del salvataggio, ma solo un controllo se<br />
l’o<strong>per</strong>azione è andata a buon fine. Viene infatti controllata la variabile “error” (riga 8), e viene<br />
impostato un messaggio da visualizzare poi all’utente, che dovrà essere avvisato se il salvataggio<br />
si è concluso correttamente oppure se ci sono stati degli errori.<br />
Tutto molto semplice come sempre!<br />
Abbiamo concluso! Cliccate su “Build and Go!” e testate il vostro programma funzionante!<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 179
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 180
Bibliografia<br />
I miei tutorial spesso sono nati prendendo spunto da altre guide trovate su Internet, scritte da<br />
altre <strong>per</strong>sone. Mi pare corretto, quindi, riportare di seguito i link da cui ho preso alcuni tutorial,<br />
in modo da dare il giusto riconoscimento ai legittimi autori.<br />
Capitolo 3: <strong>iPhone</strong> <strong>SDK</strong> Articles, “First <strong>iPhone</strong> Application”,<br />
http://www.iphonesdkarticles.com/2008/07/first-iphone-application.html<br />
Capitolo 4: <strong>iPhone</strong> Development Central, “Trash<strong>Tutorial</strong>”,<br />
http://www.iphonedevcentral.org/tutorials.php?page=View<strong>Tutorial</strong>&id=30&uid=68863015<br />
Capitolo 5: <strong>iPhone</strong> Development Central, “UIToolbar and AutoRotation”,<br />
http://www.iphonedevcentral.org/tutorials.php?page=View<strong>Tutorial</strong>&id=48&uid=79444464<br />
Capitolo 6: <strong>iPhone</strong> Development Central, “UIProgressView <strong>Tutorial</strong>”,<br />
http://www.iphonedevcentral.org/tutorials.php?page=View<strong>Tutorial</strong>&id=43&uid=34167348<br />
Capitolo 7: <strong>iPhone</strong> Noob, “Access the Address Book”,<br />
http://iphone.zcentric.com/2008/09/19/access-the-address-book/<br />
Capitolo 11: iPod Touch Fans Forum, “[<strong>Tutorial</strong>] <strong>Get</strong>ting to know Xcode/Interface Buider: PARTS<br />
I & II: UITabBar projects”,<br />
http://www.ipodtouchfans.com/forums/showthread.php?t=137183<br />
Capitolo 14: The Apple <strong>Blog</strong>, “<strong>iPhone</strong> <strong>SDK</strong> <strong>Tutorial</strong>: Build a Simple RSS reader for the <strong>iPhone</strong>”,<br />
http://theappleblog.com/2008/08/04/tutorial-build-a-simple-rss-reader-for-iphone/<br />
Capitolo 16: iPod Touch Fans Forum, “[<strong>Tutorial</strong>] Drawing to the screen”,<br />
http://www.ipodtouchfans.com/forums/showthread.php?t=132024<br />
<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>! 181
Andrea Busi<br />
“<strong>Tutorial</strong> <strong>pratici</strong> <strong>per</strong> <strong>iPhone</strong> <strong>SDK</strong>”<br />
versione 1.6, dicembre 2010<br />
! 182