Manuale IOS

154

description

Manuale utilizzo IOS

Transcript of Manuale IOS

Page 1: Manuale IOS
Page 2: Manuale IOS
Page 3: Manuale IOS

I n d I c e

Prefazione

Introduzione

Xcode: una breve panoramica

Primi passi in Xcode

I template Creare un nuovo progetto Le proprietà del progetto Interface Builder Le novità di iOS 5

Capitolo 1 - “Hello World”

Creiamolastrutturagrafica Definiamoglielementieleazioni Scriviamo il codice necessario Nascondiamo la tastiera

Capitolo 2 - Uno sguardo ai componenti base

Creiamolastrutturagrafica Scriviamo il codice necessario

Capitolo 3 - Gestiamo immagini ed eseguiamo semplici animazioni

Creiamolastrutturagrafica Implementiamo il movimento del logo

Capitolo 4 - MultiBrowser: creiamo un browser

Creiamolastrutturagrafica Creiamo la seconda vista Scriviamo il codice per aprire la pagina desiderata Gestiamo il passaggio tra le due viste

7

9

9

13

1315161821

23

23252829

33

3336

39

3941

45

45485152

Page 4: Manuale IOS

Capitolo 5 - UITableView: le tabelle

Parte1:Creiamoedefiniamolatabella Creiamo la struttura Scriviamo il codice necessario Parte2:Inseriamoalcunefunzionalità Permettiamolacancellazionediunariga La vista di dettaglio Parte 3: Implementiamo la ricerca Aggiungiamo il box di ricerca Modifichiamoimetodigiàesistenti Implementiamo la ricerca

Capitolo 6 - AccessContact: utilizziamo i contatti

Creiamolastrutturagrafica Scriviamo il codice necessario

Capitolo 7 - XML

Cosa è XML XMLnellaprogrammazioneperiOS Creiamolastrutturagrafica Scriviamo il codice necessario

Capitolo 8 - SQL

Creiamo il database Creiamolastrutturadell’applicazione Definiamolaclasse“Data” Mostriamo i valori del database Cancellazionediunelemento Inserimento di un nuovo elemento

Capitolo 9 - Creiamo un semplice lettore di feed RSS

Parte 1: Creiamo la base del lettore Creiamolastrutturadell’applicazione Definiamoimetodidelparser Visualizziamoglielementinellatabella Parte2:Miglioriamolagraficadell’applicazione Creiamolacellapersonalizzata Definiamolagraficadellacella Utilizziamolacella Parte3:Visualizziamol’articolocompleto

55

55555661616264646568

71

7173

79

79818183

87

88949699

102105

111

111111112115117117120123126

Page 5: Manuale IOS

I n d I c e

Capitolo 10 - Realizziamo il nostro “Brushes”

Parte1:Creiamolatavolagrafica Creiamolastrutturagrafica Definiamoimetodinecessari Parte2:Inseriamoleimpostazioni Creiamolastrutturagrafica Scriviamo il codice necessario Parte 3: Inseriamo il salvataggio del disegno

Conclusioni

Bibliografia

131

131131134139139142147

151

153

Page 6: Manuale IOS
Page 7: Manuale IOS

7

P r e f a z I o n e

Prefazione

Probabilmentemoltidivoistarannoleggendoperlasecondavoltaquestaprefazio-ne. Questo ebook, infatti, è giunto alla seconda versione, dopo più di due anni dalla sua prima versione. Tante cose sono cambiate in questi due anni, sicuramente non mi aspettavo un successo così grande per questa piccola guida.“TutorialpraticiperiOSSDK”ènataperracchiuderealcunitutorialsullaprogram-mazioneperiOS,chehoscrittoepubblicatoprimasuBubiDevsepoisudevAPP.Comehogiàdettopiùvolte,questolibrononvuoleessereunmanualeesaurienteosostituirsialladocumentazioneufficialediApple(acuidovetesemprefarriferimen-to),masolounostrumentoperchièalleprimearmi,oppureperchivuoleimpararequalcosacheancoranonsa.Trovereteunaseriediguidepratiche,daseguirepassoperpasso,commentateespiegate,perconsentireatuttidiimparareecapirequellochevienefatto.Illibroviguideràprimainunaseriedisemplicitutorial,incuiverrannopresentatieanalizzatigliaspettieicomponentibasedellaprogrammazioneperiOS.Gliultimiduecapitoli,invece,vipermetterannodicrearedueapplicazionivereeproprie,inmodocheab-biate un quadro d’insieme generale.

Ringraziochiunqueleggaquestepagine,etuttiquellicheinpassatolehannogiàlette.Sperochequestolibropossainsegnarviqualcosadinuovo,edaiutarvinelvostroscopo,siaessolavorativooperpurapassione(comelamia).

Ringrazio lamiafidanzata,checontinuaasopportarmiesostenermi, seppurnonsappianientediprogrammazione!Probabilmenteancheleiavràimparatoqualcosaaforzadisentirelemiespiegazioni..

RingrazioilmiograndeamicoMatteo,checongrandepassioneededizionesiède-dicatoall’impaginazionediquestaversione,conferendogliunaspettodavveropro-fessionale.

RingrazioSteveJobs,chepurtropporecentementeciha lasciato,peravercreatoApple,qualcosachevaoltreunasempliceazienda.

E ricordatevi, solo essendo curiosi e affamati è possibile scoprire e creare qualcosa di nuovo e veramente innovativo.

“Siate affamati, siate folli.”

Page 8: Manuale IOS
Page 9: Manuale IOS

9

I n t r o d u z I o n e

I. Introduzione

Se avete acquistato e state leggendo questo ebook sicuramente termini come iPhone,AppStore,appealtriancoranonvisarannonuovi.Nonmidilungherò,quin-di,sull’impattochedispositivicomeiPhoneeiPadhannoavutonelsettoremobile,perchésonosottogliocchiditutti.

Sviluppareapplicazioniperquestidispositivièdiventataunapratica(espessoun’esi-genza)moltodiffusa:ragazzialleprimearmichevoglionoscoprirequestomondo,maancheaziendecheoperanodaanninelsettoreICTchesiaffaccianosuquestinuovi dispositivi sempre più presenti nella vita quotidiana. Tutti, insomma, parlano di iOSedellesuepotenzialità.Creareun’applicazione,venderlainAppStoreeotteneredeiricavieconomicièormaiallaportataditutti:bastanounalicenzadasviluppatore,unMaceunpo’distudio.Quindi,nulladicomplesso!

Piùavantivedremocos’èlalicenzadasviluppatoreecomesiottiene,perilmomentosappiatechenonènecessarioaverlaperiniziareasviluppareapplicazioniperiPhone.Quellodicuiavetebisogno,perora,èunMac(conOSXLion)eXcode.

Xcodeèilnomedell’ambientedisviluppocreatodaApplechepermettedirealizzareapplicazionisiaperdispositiviiOScheperMac.XcodeèdisponibilesulMacAppStore gratuitamente (lo trovate a questo indirizzo, http://itunes.apple.com/it/app/xcode/id448457090?mt=12):unavoltascaricatoeinstallatosieteprontiperiniziarelavostraavventuradaprogrammatori!

Xcode: una breve panoramicaQuando parliamo di Xcode ci riferiamo, solitamente, all’insieme dei tool di sviluppo cheApplemetteadisposizione.Dopol’installazione,troveretetutti iprogrammidicuiavetebisognonellacartella“/Developer/Applications”.Glistrumentisonodavveromoltiealcunisonocomplessi(tranquilli,inquestoebookutilizzeremosolol’editorXcode). PercompletezzaeccoviunabrevedescrizionedeiprogrammicheApplecifornisce:•Dashcode,èunutiletoolconcuipotremocrearepagineweb,widget(destinatiallaDashboarddiMacOSX)ealtro.

•Instruments,permettedianalizzareevalutareleprestazionidellenostreapplica-zioni(interminidiconsumodimemoria,utilizzodelprocessore,etc).Èdestinato,ovviamente, agli sviluppatori più esperti.

•Quartz Composer,èuntoolchepermettedicreareanimazioniedeffettigrafici,dautilizzarepoiinaltriprogrammi.

•Xcode,è l’ambientedisviluppoveroeproprio.Saràqui, infatti,cheandremoacreareinostriprogetti,scrivereilcodiceecompilareiltutto.Dallaversione4haintegratoalsuointernoInterfaceBuilder,un’ottimotoolchecipermettedicrearel’interfacciagraficadellenostreapplicazioni,iltuttoinmanierasempliceeveloce.

Page 10: Manuale IOS

10

Da qui possiamo riaprire velocemente uno degli ultimi progetti a cui abbiamo lavorato, oppurecrearneunonuovo.Èanchepossibileaprireladocumentazione(cosachedo-vrete imparare ad abituarvi a fare) oppure andare direttamente al portale sviluppatori.

Fig. A: Schermata di benvenuto di Xcode

AnalizziamopiùneldettaglioXcode.All’aperturasipresentaquestaschermata:

Page 11: Manuale IOS

11

I n t r o d u z I o n e

Quandoapriamounprogetto(nuovooesistente)Xcodesipresentacosì:

Comepotete vedere dall’immagine, ci sono diverse sezioni che lo compongono. Inaltotroviamola“Toolbar”,un’ampiabarrachecifornisceimmediatoaccessoadal-cunefunzioni.Cliccandosulpulsante“Run”potremocompilareedeseguireilnostroprogetto,cheverràavviatosulsimulatoreosuldevicecollegatoalnostrocomputer. Afiancotroviamounmenùatendinaincuipossiamoselezionareappuntodoveese-guire il progetto. Alcentroundisplay,simileaquellodiiTunes,ciforniscedelleinformazionichecam-bianoasecondadell’operazionechestiamoeseguendo:civerrannonotificatiglierrori,l’avanzamentodellacompilazioneedaltreinformazionicheimparereteaconoscere.Nella parte destra, invece, troviamo tre piccoli bottoni raggruppati con la dicitura “View”,checipermettonodimostrareonasconderelevariearee(nell’ordine:“Navi-gation Area”,“Editor Area”,“Utility Area”e“Debug Area”).

La“Navigation Area”cipermettedivedereilnostroprogettoetuttiifilechelocom-pongono.Troveremoleclassi,leimmaginiinserite,iframeworkutilizzati.Nellapartesuperiorediquestaareacisonoalcuneicone,checipermettonodiaccedereadaltresezioni.Grazieaquestepotremoeseguiredellericerchemirateall’internodelcodice(“Searchnavigator”),oppurevisualizzareglieventualierroriogliwarning risultantidallacompilazione(“Issuenavigator”).

“Editor Area”èlaparteprincipaledell’editor,incuipotremoscrivereilcodicedellenostreapplicazioni.Forniscedellefunzionifantastichecomel’auto-completamento,lacorrezioneautomaticadeglierrorietantoaltro.Tuttefunzionicheimpareretepianpianoadapprezzare.

Fig. B: Sezioni che compongono Xcode

Page 12: Manuale IOS

12

“Utility Area” fornisceaccessoalla libreriadegli oggetti (indispensabilequandosilavora in Interface Builder). Permette inoltre di accedere velocemente alla documen-tazionediunoggetto,graziealcomodo“QuickHelp”cheèsempreinfunzione.

“Debug Area”è, infine,lasezionecheforseodieretequandovitrovereteadutiliz-zarla:quivengononotificatieventualierrorichemandanoinbloccol’applicazione,oppureimessaggilanciatidaparticolariistruzioni.Anchevoi,comunque,sareteingrado di far stampare dei messaggi in quell’area, vedremo poi come. In questa se-zioneèanchepossibile,infasedirun-time,vederelostatodellevariabiliolostackdellechiamateallefunzioni.

CisarebberoaltrimilleaspettidiXcodedaanalizzareediscutere,maprobabilmenteservirebbe un libro solo per quello. Per avere una panoramica completa su que-stostupendostrumento,viconsigliodiselezionare“Learn about using Xcode”nellaschermatainizialechesipresentaquandoapriteXcode.

Page 13: Manuale IOS

13

P r I m I P a s s I I n X c o d e

II. Primi passi in XcodeDopoavervistobrevementecomeXcodeèstrutturato,èvenutoilmomentodiinizia-readutilizzarloevederecosaciproponeperrealizzareinostriprogetti.

I templateQuandoselezioniamo“CreateanewXcodeproject”civienepropostalaseguenteschermata:

PotetenotarecheXCodeciforniscevaritemplate,ovverodellestrutturegiàpronte,checipermetterannodicreareapplicazionisullostilediquellenative.Nondovremoperderetempo,quindi,perreplicarelostiledellealtreapplicazioniperchéèApplestessachecelimetteadisposizione.

Analizziamoora ivari templatechecivengono fornitiedosserviamo i treesempiriportati nella pagina seguente.

•Document-Based Application,generaun’applicazionelacuistrutturabasedeidatièundocumento.Essopuòesseresiaundocumentointernoall’applicazione,siaunaseriedidatiricavatidaiCloud(ilnuovosistemadicloudintrodottodaApplecon iOS 5).

Fig. C: Creazione di un nuovo progetto in Xcode

Page 14: Manuale IOS

14

•Master-Detail Application,generaun’applicazionecompostadaunatabella,unabarradinavigazioneeunavistadidettaglio.Per farviunesempio,pensateallastrutturadi“Impostazioni”nelvostroiPhone:aveteunabarrainaltochevisualizzailtitolodellasezionecorrente,evipermette,tramiteunbottone,ditornareallase-zioneprecedente.Questabarravienechiamata“NavigationBar”.Èutilepercreareapplicazionicon tabelle, incuivogliamomostrareanche le informazionisuivarielementi.LostessotemplatepermetteanchedicrearetabelleappositeperiPad(le“SplitView”).

•OpenGL Game, questa è sicuramente la tipologia più complessa, in quanto si basa sullatecnologiaOpenGL,sfruttataprincipalmenteperrealizzarevideogiochioani-mazionigrafichecomplesse.Inquestolibrononanalizzeremoquestatipologiadiapplicazioni.

•Page-Based Application,fornisceunastruttura“apagine”,comeunasortadilibro,sfogliabile scorrendo il dito da destra verso sinistra.

•Single View Application,fornisceun’applicazionevuota,senzanessunaimplemen-tazioneparticolare.Questotemplateècompostounicamentedaunafinestracheviene richiamata all’avvio dell’applicazione, chiamata “ViewController”. Questosaràilpuntodipartenzaperquasituttiinostritutorial.

•Tabbed Application,fornisceun’applicazioneconla“tabbar”,ovverolabarraneracompostadapiùsezioni(adesempioquellachetrovatenell’applicazionenativa“Musica”).

•Utility Application,questatipologiaimplementaunmenùchevienerichiamatoruo-tandolaschermataprincipale.Ancheinquestocaso,potetetrovareunasimilitu-dineconl’applicazione“Meteo”:sepremetesulla“i”presenteafondopagina,laschermataruoteràevipermetteràdimodificareleimpostazionidell’applicazione.

•Empty Application, fornisce solo un delegato per la nostra applicazione, senzanessunelementografico.Èdestinatoagliutentipiùesperti,chevoglionocrearelalorostrutturapersonalizzata.

Fig. D: Master-Detail Application Fig. E: Tabbed Application Fig. F: Utility Application

Page 15: Manuale IOS

15

P r I m I P a s s I I n X c o d e

Creare un nuovo progettoIn ogni tutorial che vedremo, sarà necessario creare unnuovoprogetto.Per fareciò,apriteXcodeedallaschermatadibenvenutoselezionate“CreateanewXco-de project” (oppure, in alternativa, selezionare “File -> New -> New Project...”). Siapriràlafinestraconlasceltadeltemplate,cheabbiamoappenaanalizzato. Sceglieteiltemplatedesiderato(generalmentesarà“SingleViewApplication”)eclic-catesu“Next”.

Nellaschermatasuccessivadobbiamodefinirealcuneproprietàdelprogetto.•Product Name,èilnomedelnostroprogettochesolitamentecoincideconilnomechedaremoall’applicazione(nonpreoccupatevi,ilnomedell’apppotretecambiarloin qualsiasi momento).

•Company Identifier,èunidentificativounivococheassegnateallavostraapplica-zione.Perconvenzionedeveavereunaformacomequesta“com.companyname.app_name”.Nelmiocasohoinserito“net.bubidevs”(il“.app_name”vieneaggiun-to in automatico da Xcode).

•Class Prefix,quipoteteimpostareunprefissocheverràantepostoatutteleclassichecreerete(peroranonènecessario).

•Device Family,quiscegliamoidispositiviacuièdestinatalanostraapplicazione.PotremosceglieredidestinarlasoloadiPhone(comefaremonoipertuttiituto-rial),soloadiPad,oppurecreareun’applicazioneuniversale,destinataquindiadentrambi i dispositivi.

•Use storyboard,spuntandoquestaopzioneutilizzeremounnuovosistemaperladefinizionedell’interfacciagrafica.EssendounanovitàdiiOS5,hopreferitononutilizzarlainquestolibro,preferendoil“vecchio”sistemaafile“.xib”.

•Use Automatic Reference Counting,spuntandoquestaopzionesfrutteremoilnuo-vosistemadigestionedellamemoria,introdottoanch’essoconiOS5.Piùavantivispiegheròmeglioquestanovità,cheutilizzeremopersemplificarelosviluppo.

• Include Unit Test, questa opzione vi creerà anche delle classi destinate al testdell’applicazione.Peroranonutilizzatela.

Page 16: Manuale IOS

16

Impostate le proprietà di questo primo progetto come nello screen seguente:

Cliccateancorasu“Next”eselezionate,infine,ilpercorsoincuivoletesalvareilpro-getto,premendopoi“Create”.Avretecosìcreatoilvostroprimoprogetto!

Le proprietà del progettoUnaspettomoltoimportanteechespessocreaalcunedifficoltàachièalleprimearmi con Xcode sono le proprietà relative ad un progetto.

Appenaabbiamocreatoilnostroprogetto,civengonomostratelesueproprietà(chepossiamo visualizzare ogni volta che desideriamo semplicemente selezionando ilnome del progetto nella navigation area di Xcode).

Èbeneanalizzareecomprenderefindasubitoquesteproprietà,perchéspessosonofattorimolto importanti nello sviluppo di un’applicazione. Alcune di esse sono lestessechevisonostaterichiestequandoavetecreatounnuovoprogetto,mentrealtre sono nuove.

Fig. G: Proprietà del progetto

Page 17: Manuale IOS

17

P r I m I P a s s I I n X c o d e

Nellaprimasezionetroviamoalcuneproprietàraggruppatenelgruppo“iOSApplica-tionTarget”,eccoleneldettaglio:•Identifier,èil“CompanyIdentifier”dicuiabbiamodiscussopocofa.

•Version e Build,indicanoilnumerodiversionedellavostraapp.Èunnumeroche,solitamente,iniziada1.0perlaprimaversione,esiincrementaconivariupdatecherilasciate(adesempio1.1,1.2o2.0).

•Devices,indicaidispositiviconcuilavostraapplicazioneècompatibile(comeprima).

•Deployment Target,quiandremoaselezionarelaversionediiOSconcuivogliamochesiacompatibilelanostraapplicazione.Questoènecessarioinquanto,conilrilasciodinuoveversionidelsistemaoperativo,vengonoaggiunteanchenuovefunzionial-l’SDK(lecosiddetteAPI).Quindi,un’applicazionescrittaecompilataperiOS5potreb-benonfunzionaresudispositiviconiOS4.2installato(spessoèproprioimpossibileinstallarlainquantol’AppStorecontrollaquestacompatibilitàinfasediinstallazione). Alcontrario,secompiliamol’applicazioneperlaversione4.0funzioneràsicura-mentesuiOS5(amenochenonutilizziatedelleAPIconalcunibug).Èimportante,quindi,scegliereconcuralaversionedautilizzare,pernonescluderepartedegliutentidall’utilizzodellanostraapplicazione.

Lasecondasezione,“iPhone/iPodDevelopmentInfo”permette,tralealtrecose,diselezionareleorientazionisupportatedallanostraapplicazione:portraitelandscape,specificando,inoltre,ilversodiorientamentosupportato.Inquestasezionesipossono impostareanche le icone (indimensionenormaleeadattealRetinaDisplay)elesplashscreen.Visegnalocheèanchepossibilecam-biarelafinestraprincipalechevienecaricataall’avviodell’applicazione:solitamenteèla“ViewController”che,almenoperora,viconsigliodinoncambiare.

Fig.H: Proprietà complete del primo progetto

Page 18: Manuale IOS

18

Interface BuilderCon il nuovo Xcode 4 Interface Builder è un componente integrato in Xcode, e non è piùun’applicazioneesterna.Essocipermettedicrearegraficamentelenostreinter-facce,senzadoverricorrerealungherighedicodice.

Nota: alcuni “puristi” del codice sono contrari a questo approccio mediante IB, perché lo ritengono uno spreco di memoria. Sicuramente scrivere componenti grafici via codice fa risparmiare qualcosa in termini di prestazioni, però per applicazioni semplici o non troppo complesse non ritengo che questo sia un fattore da tener molto in considerazione. In fondo, se Apple ha sviluppato e insistito con questo strumento un motivo ci sarà...

TornandoaXcode,selezionate il file “ViewController.xib”cheverràaperto tramitel’editor di IB mostrandoci questi elementi:

Fig. I: Apertura di ViewController.xib in Interface Builder

Fig. L: Inspector

Nellapartesuperioredi“UtilityArea”troviamo“Inspector”,sicuramentelapartepiùimportante di Interface Builder.

Page 19: Manuale IOS

19

P r I m I P a s s I I n X c o d e

Cipermettediimpostarequalsiasiproprietà,relativaadognioggetto(dallavistaalsingolobottone).Potremo,quindi,modificarel’aspettodeglioggetti,modificarneledimensioniecollegareleazioni.Insomma,potreteagiresumoltissimiaspetti(iltuttosenzascrivereunarigadicodice).Lesezionichelocompongonosonoleseguenti:•File,ciforniscedelleinformazionisulfilecheabbiamoaperto(adesempioilper-corso)epossiamoinserirenuovelocalizzazioni(ovveroaggiungerelatraduzioneper altre lingue).

•Quick help,visualizzaunabreveguidadelcomponentecheabbiamoselezionato,ricavandoleinformazionidirettamentedalladocumentazioneufficiale.

•Identity, in questo pannello sono presenti alcune voci relative al progetto e all’ac-cessibilità.Inquestoebooknonutilizzeremomaiquesteproprietà.

•Attributes, qui possiamo variare gli attributi generici dei nostri oggetti, ad esempio ilcolore,ladimensionedelfont,edaltreproprietàcheimpareremopocoallavolta.

•Size,questasezionepermette,comedicelaparolastessa,dimodificareledimen-sionidell’oggetto,edimodificarneanchelaposizioneel’ancoraggio(ovverodovedeveesserefissato:questosaràfondamentalequandosiimplementalarotazionedellaschermata).

•Connections,èunodeipannelliprincipali.Quiandremoacollegareleazioniaglioggetti.Cosasignifica?Ve lospiegoconunesempio.Supponiamodiavereunbottonenellanostravista,evogliamochequandovienepremutovengascritto“Ciao”inunacaselladitesto.Creeremo,quindi,un’azionechesioccuperàdiscri-vere“Ciao”.Dovremopoicollegarequestaazionealbottone,inmodochequandol’utente preme il bottone, viene eseguito il comando desiderato. Spesso questi collegamenti vengono fatti in maniera automatica da Xcode ma a volte dovremo essere noi a crearli.

Semprenella“UtilityArea”troviamola“Library”,ovverolalibreriachecontienetuttiglielementichepossiamoutilizzarepercrearelenostreinterfacce.

Fig. M: Library di U

tility Area

Page 20: Manuale IOS

20

Scorrendola potrete notare moltissimi componenti, come bottoni, label di testo, vi-ste,barreemoltoaltro.Tuttiquestielementipossonoessereutilizzatinellenostreap-plicazioni.Perinserirlibastatrascinareuncomponentenellaschermatadell’applica-zioneecollocarloapropriopiacimento.Questoèveropertuttiicomponentitrannei“Controllers”,chepotretericonoscereperchéhannounosfondogiallo/arancione.Questisonoelementidiversi,chehannoilcompitodirappresentarealtrioggetti(adesempioclassiocontroller),manonelementigraficiveriepropri.

Nellapartesinistradell’editor(afiancodellavistachevieneproposta)c’èunpannellochemostraleiconedialcunielementi(Fig.N).

Cliccatesulpulsantinochetrovatenellasuapartebassaperespanderetalemenù(Fig.O).

Fig. O: Elementi di ViewController (2)Fig. N: Elementi di ViewController (1)

Quipotretevedere icomponentidelvostrofile .xib (ovvero il filedi interfaccia). Ilcomponenteprincipaleèil“File’sOwner”:letteralmenteessoèilproprietariodellanostra vista, ovvero è l’elemento che si occupadi gestirne tutti i comportamentirelativi. Tale classe, infatti, dovrà impostare il testonelle label,modificare il com-portamentodeglioggettiecosìvia.Seloselezionateevispostatepoinell’“IdentityInspector”vedretecheilproprietariodiquestavistaèlaclasse“ViewController”:èproprio essa a gestire il comportamento di questa vista.

Abbiamo così completato la panoramica sull’Interface Builder. Mi pare inutile, per ora,dilungarmiinaltriaspettichevisarannosicuramentepiùchiariefamiliariconunpo’dipratica.Inpochissimotempo,nonriusciretepiùafareamenodiInterfaceBuilder!

Page 21: Manuale IOS

21

P r I m I P a s s I I n X c o d e

Le novità di iOS 5ComeognimajorreleasediiOS,Applehaintrodottopiùdi1.500nuovifunzioniperglisviluppatori.Capiretechecitarleedescriverle tutteèun’impresa impossibileecertamentenonutileperchièalleprimearmi.Lanovitàcheciinteressamaggiormente,echeanalizzeremoinquestolibro,èl’ARC.

L’ARC(AutomaticReleaseCounting)èunnuovometododigestionedellamemoria,cheintroducedellefunzionialivellodicompilazionepersemplificarnelagestione.Prima di iOS 5 quando si creavano oggetti ed elementi era necessario occuparsi anchedellalorogestione:quandononeranopiùnecessariandavanoeliminati,uti-lizzandofunzionicome“release”.Grazieall’ARCnonsaràpiùnecessariooccuparsidiciò,perchéverràfattoinautomaticodalcompilatore.Attenzione,nonsitrattadiungarbage-collectorcomepotetetrovareinJavaoinaltrilinguaggi,masonodellesemplificazionicheXcodeeilcompilatorefannopernoi.Ovviamenteapprofondire-mo questi aspetti man mano li troveremo nell’ebook.

OracheaveteavutounapanoramicasuXcodeesucomefunziona,ègiuntal’oradicrearelanostraprimaapplicazione!

Page 22: Manuale IOS
Page 23: Manuale IOS

23

c a P I t o l o 1H e l l o Wo r l d

1. “Hello World”

Comeda“tradizione”iniziamolanostraavventuranelmondodellaprogrammazioneperiPhonetramiteilclassicissimo“HelloWorld”.

Lanostraprimaapplicazionesaràdavveromoltosemplice:chiederemoall’utenteilsuonome(adesempioTizio)eallapressionediunbottonefaremoapparireilmes-saggio“CiaoTizio”.Nientedicomplicatoquindi,peròcercatedicapirebenetuttiipassaggi, in modo da non avere lacune su questi concetti davvero basilari.

Creiamo la struttura graficaIniziamocreandounnuovoprogettoditipo“SingleViewApplication”echiamiamo-lo“HelloWorld”.Nellafinestrasuccessivatogliamolaspuntaa“Usestoryboard”e“IncludeUnitTest”mentreassicuriamocichesiaspuntatalavoce“UseAutomaticReferenceCounting”esiaselezionato“iPhone”comedevice.

Apriamoquindiilfile“ViewController.xib”:dobbiamocrearelastrutturagrafica,chedeveesseresimileall’immagineriportatanellapaginasuccessiva(Fig.1.2).

Fig. 1.1: Creiamo il progetto “Hello World”

Page 24: Manuale IOS

24

Come potete osservare, ci sono tre componenti principali:•una“UITextField”incuil’utentepotràinserireilproprionome;

•un“UIButton”,conlascritta“Saluta!”,chel’utentedovràpremereperfarapparireilsaluto;

•due“UILabel”,unaconlascritta“Inserisciiltuonome”(equestaservesoloperrenderepiùintuitivoilnostroprogramma),l’altrapostaacentroschermo(checon-tienelastringaLabel).Èimportanteimpostareledimensionidiquestaultimalabelinmodocheoccupituttalalarghezzadellavista,altrimentiavremoproblemiquan-do andremo a stampare il messaggio di saluto in seguito.

Tramite“AttributeInspector”possiamodefinirealcuneproprietàperquestioggetti.SelezioniamoadesempiolaUITextField,eimpostiamoiseguentivalori:•“Capitalize”: “Words” (ovveroquando l’utente iniziaadigitare ilproprionome laprimaletteravienescrittainmaiuscolo);

•“Corrections”:“No”(disabilitiamolacorrezioneautomaticaperquestocampo);

•Spuntiamol’opzione“Clear When Editing Begins”(cancelleràilcontenutogiàpre-sentenonappenal’utenteselezionailcampo).

Avostropiacerepoteteancheimpostarealtreproprietà,provatenealcuneperpren-deremeglioconfidenzacon ilprogramma.Potete,adesempio,modificare il fontdelle due label oppure il colore di sfondo della vista.

Primadiproseguire,diamoun’occhiataaciòchecomponequestofile(lotrovatenelpannello alla sinistra della vostra vista, riportato nella pagina successiva, Fig. 1.3).

Fig. 1.2: View

Controller di “H

ello World”

Page 25: Manuale IOS

25

c a P I t o l o 1H e l l o Wo r l d

Potetenotaretreelementi,cheXCodehagiàdefinitopernoi.•“File’s Owner”,comedicelaparolastessaèilproprietariodelfile.È,insostanza,laclassechegestiscelanostravista,ovverochegestisceognisingoloaspetto.Nelnostrocasosaràlaclasse“ViewController”,dovepoiandremoascrivereilcodicenecessario.

• “First Responder”, è un oggetto che nella programmazione per iPhone non hamoltosenso.Èun“relitto”derivatodallaversionediCocoaperMac,quindipoteteanchedimenticarvicheesista.

• “View”, è la nostra vista, ovvero la schermata che abbiamodefinito. In questocasoneabbiamounasola,manullacivietadidefinirnesvariateerichiamarlepoianostropiacimento.All’internodell’oggetto“View”potetevedereglielementicheabbiamoinseritotramiteIB,chefannoorapartedellavista.

Definiamo gli elementi e le azioniOravediamocomeèpossibilecollegareglielementigraficicheabbiamoappenain-seritocondeglioggettinelcodice.Xcode4permettedifaretuttociòconunsistemadavvero semplice e veloce.

Nella“Toolbar”diXcodecliccatesulseguentepulsante(sitrattadell’“Assistanteditor”):

Fig. 1.3: Elementi di ViewController.xib

Fig. 1.4: Assistant Editor

Page 26: Manuale IOS

26

L’editorverràdivisoindue:asinistravedremolanostrainterfacciagrafica,mentreadestralarelativaclassechelogestisce.Dovresteavere,quindi,unaschermatacomequesta:

Fig. 1.6: Creazione delle connessioni

Fig. 1.5: Utilizzo dell’Assistant Editor

Selaclassechevivienemostratanonèquellacorretta,tramitelabarrachetrovatesopra ilcodicepotretenavigaretra ivarifilechecompongonoilprogettoeaprirequellacorretta(chedeveessere“ViewController.h”)

CliccatesullaUITextFieldetenendopremutoilpulsante“ctrl”cliccate(tenendopre-muto)partendodallatextfield:vedretecomparireunarigablu,trascinatelafinoalfiledellaclasse.Seaveteeseguitocorrettamentequestaoperazioneviappariràunpop-up simile al seguente:

Page 27: Manuale IOS

27

c a P I t o l o 1H e l l o Wo r l d

Questovipermetteràdicreareduetipidielementi(campo“Connection”):•“Outlet”:permettedicollegareglielementiinseritiinIBconoggettinelcodice;

•“Action”:questoservepercrearedelleazioni,chedevonoessereassociateapar-ticolari eventi.

Selezioniamo“Outlet”einseriamocomenome“fieldNome”.Ripetiamo lo stesso procedimento con la label destinata ad ospitare il messaggio e chiamiamola“labelSaluto”.

Dobbiamocompletareicollegamenticonun’azione:quandol’utentepremesulbot-tonevogliamochevengarichiamatoundeterminatometodo,cheavràilcompitodimostrare il messaggio nella label predisposta.

Ancoraunavoltaeseguiamolostessoprocedimentopartendodalbottone;allacom-parsadelpop-upselezioniamo“Action”cometipologiadellaconnessioneechia-miamolo“saluta”:

Fig. 1.7: Creazione dell’azione

Codice 1.1: File di interfaccia ViewController.h

Abbiamocompletatoleconnessioninecessarie!Seabbiamoeseguitotuttiipassag-gi correttamente avremo la classe così composta:

12345678910

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (strong, nonatomic) IBOutlet UITextField *fieldNome;@property (strong, nonatomic) IBOutlet UILabel *labelSaluto;

- (IBAction)saluta:(id)sender;

@end

Page 28: Manuale IOS

28

Idueoggettigraficisonostatidichiaratitramitedue“property”cheprestoimparereteaconoscere.Perorasappiatecheessevipermettonodiaveredellevariabiliaccessibiliancheall’esternodellaclasse,inquandogeneranoautomaticamenteimetodigetteresetternecessari.Possiamoanchenotarecheentrambeledichiarazionisonoprece-dutedallaclausola“IBOutlet”,cheindicaadInterfaceBuildercheèpossibilecollegarequestometodoadunelementografico.InquestocasoilcollegamentoèstatogiàfattodaXcode.Dopoquesteduedichiarazioni,trovatel’intestazionedelmetodo“saluta:”,eancheinquestocasotrovateunaclausola”IBAction”:anchequestastaasignificarechel’azioneècollegataaduncomponentediInterfaceBuilder.Essa,infasedicom-pilazione,corrispondeadunclassico“void”,ovverounmetodosenzanessunritorno. Ilparametro“sender”èinvecel’identificativodell’oggettochehachiamatoilmetodo. Grazieaquestoparametropotretecollegarelostessometodoapiùoggetti,ecapirepoidachièstatoinvocatopropriograzieall’oggetto“sender”.

Scriviamo il codice necessarioDobbiamooraimplementareilmetodo“saluta:”,chesioccuperàdileggereilnomeinserito dall’utente e stampare il messaggio di benvenuto nella label predisposta. Spo-stiamocinelfile“ViewController.m”(possiamoanchedisattivarel’“Assistanteditor”).

Codice 1.2: Metodo “saluta:”

12345678910

1112

- (IBAction)saluta:(id)sender { // leggiamo il nome inserito dall’utente NSString *nome = self.fieldNome.text; if (nome.length == 0) { // l’utente non ha inserito nessun nome self.labelSaluto.text = @”Ciao Anonimo!”; } else { // salutiamo l’utente con il nome che ha inserito self.labelSaluto.text = [NSString stringWithFormat:@”Ciao%@”,nome]; }}

Nota: Il primo file che abbiamo modificato aveva estensione “.h”: questa estensione indica che si tratta di classi di intestazione, ovvero dove vengono definiti i metodi e i componenti necessari, ma non vi è alcuna implementazione dei metodi. I file con estensione “.m”, invece, contengono tutte le imple-mentazioni dei metodi, ovvero il codice delle varie funzioni. Questa suddivisione permette di avere un codice più ordinato e più leggibile.

Quando aprite il file “.m” noterete che Xcode ha già inserito del codice per noi.Troverete,adesempio,dueistruzioni“@synthesize”,chedevonoesserenecessaria-menteinseritequandosidichiaranodelle“@property”.Neimetodi“viewDidLoad”e“viewDidUnload”troveretedelleistruzionichevengonoeseguitequandolavistavienecaricataoppurechiusa.Neiprossimitutorialandremoamodificareanchetalimetodi.Peroradobbiamodefiniresoloilmetodo“saluta:”,chetroveretegiàdefinitoinfondoalla vostra classe. Inserite il seguente codice:

Page 29: Manuale IOS

29

c a P I t o l o 1H e l l o Wo r l d

Analizziamoilcodicechedefinisceilnostrometodo“saluta:”.Intalemetodononfaccia-moaltrocheleggereilnomeinseritodall’utente(tramite“fieldNome.text”,checiresti-tuiscelastringacontenutanellaUITextField)eassegnarloallavariabile“nome”(riga3).Tramiteuncostrutto“if”(dallariga5alla11)andiamopoiacontrollaresetalestringaèvuota(equindil’utentehapremutoiltastosenzainserirenessunnome)oppuresevièun valore. Ovviamente inseriamo due messaggi di saluto diversi a seconda del caso.

Particolareattenzionemeritapartedell’istruzioneallariga10,edinparticolareque-staporzionedicodice:“@“Ciao %@”,nome”.•“@”,laprimachiocciolastaadindicarecheciòchesegueèunastringa.Lasintassièsemprelastessaepuòessereschematizzatanelseguentemodo:@“stringa_de-siderata”.Dovretesempreutilizzarequestoformatoquandoutilizzateunastringa.

•“%@”,quandotrovateun%inunastringa,significacheliciandràilvalorediunadeterminatavariabile.Nonacasodopo lastringa trovare lavariabile “nome”: ilcontenutoditalevariabilenomeandràinseritoalpostodi%@.Seavessimodo-vutoinserire ilvalorediunavariabileditipofloatavremmousatolasintassi%f.Vedremoparecchiesempineiprossimitutorial.

Abbiamo concluso! Cliccate sul bottone “Run”: se non avete commesso errorinell’inserire ilcodicesiavvierà l’iPhoneSimulatorepotretetestare ilvostroprimoprogramma!

Nascondiamo la tastieraProvatead inserireunnomeeapremere il tasto“Invio”della tastieracheapparesull’iPhone:noteretecheessanonsichiude.Sitrattadiunerrore?Larispostaèno.Ènormale,inquantononabbiamodefinitonessunaazionechenascondalatastiera.Persistemarequestoinconveniente,apriamoilfile“ViewController.h”emodifichia-mol’intestazionenelseguentemodo:

Codice 1.3: Nascondere la tastiera passaggio 1

1 @interface ViewController : UIViewController <UITextFieldDelegate>

Abbiamoaggiunto“<UITextFieldDelegate>”,ovverolanostraclassedeveimplemen-tare il delegato della classe UITextField. Parleremo più avanti di cosa siano i delegati, perorasappiatechesonodeicomportamenticomuniadelleclassidioggetti.Fatto ciò, andiamo nel file “ViewController.m” e inseriamo, in un qualsiasi punto,questo metodo:

Codice 1.4: Nascondere la tastiera passaggio 2

1234

- (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return YES;}

Page 30: Manuale IOS

30

Questoèunmetododeldelegato“UITextField”.Essoviene richiamatoquandosipremeiltasto“Return”dellatastiera.L’istruzioneallariga2toglie latextfielddalprimorisponditore,equestocausalascomparsa della tastiera.

Manca,però,ancoraunapiccolacosadafare.Torniamoalfile“ViewController.xib”ecliccatesullaUITextFieldall’internodellavista.Apriteancheil”Connectionsinspec-tor”nell’UtilityAreaenoteretecomeprimoelemento“delegate”:

Fig. 1.8: Connections Inspector della text field

Clicchiamosulpallinoafiancodelnomeecolleghiamoloconil“File’sOwner”chetroviamoalla sinistradella vista. In pratica, abbiamodetto che il delegatodi taleoggettoègestitodallaclasse“ViewController”.Seaveteeseguitolaconnessioneinmaniera corretta avrete il seguente risultato:

Fig. 1.9: Connessione del delegato della text field

Siamoprontipertestarelanostraapplicazione!Cliccatesu“Run”eprovatelavostraprimaapplicazionepienamentefunzionante!

Page 31: Manuale IOS

31

c a P I t o l o 1H e l l o Wo r l d

Fig. 1.10: App 1 “HelloWorld”

Page 32: Manuale IOS
Page 33: Manuale IOS

33

c a P I t o l o 2E l e m e n t i P r i n c i p a l i

2. Uno sguardo ai componenti baseInquestosecondocapitolodaremounosguardoadalcunicomponentibasilari,cheviritrovereteadusarespessonellevostreapplicazioni.Creeremounasemplicissimaapplicazione,incuiverràmostrataun’immagine,dicuipotremoregolarelatraspa-renza.Tramiteunsegmentedcontrolsaràpossibileanchecambiarel’immagine.Unbottone,infine,permetteràdiaprireunpop-upchemostreràilvalorecorrentedellatrasparenzadell’immagine.

Disuol’applicazionenonhaunagrandeutilità,peròcipermetteràdianalizzarealcu-nicomponentimoltoutilizzatinelleapplicazioniperiPhone.

Creiamo la struttura graficaCreiamounnuovoprogettodi tipo“SingleViewApplication”echiamiamolo“Ele-mentiPrincipali”.Comesempreassicuriamociche“Usestoryboard”e“IncludeUnitTest”sianodisattivati.Apriamoquindiilfile“ViewController.xib”einiziamoadefinirela nostra interfaccia, inserendo i seguenti componenti:

Fig. 2.1: Schem

a elementi da inserire

Dobbiamomodificareunpaiodiproprietàde-gli elementi. Iniziamo selezionando il segmented controle aprendo la sezione “Attributes Inspector”dell’Utility Area.

Cerchiamolaproprietà“Segments”eaumen-tiamolaa3:vogliamo,quindi,checisianotresezioninell’oggetto.

Fig. 2.2: Segm

ented Control

Page 34: Manuale IOS

34

Clicchiamopoisulnomediognisezioneecambiamolo,inserendo“Prima”,“Secon-da”e“Terza”.Eccoilrisultato:

Fig. 2.3: Struttura grafica com

pleta

Oradobbiamosolomodificareivaloridelloslider.Selezioniamoloe,semprein“Attri-butes Inspector”,settiamoilvalore“Minimum”a0,mentreil“Maximum”a1.

Fig. 2.4: Modifica valori dello Slider

Questamodificacipermetteràdiutilizzareilvalorecontenutonellosliderperlatra-sparenzadell’immagine(cheaccettasolovaloricompresitra0e1),senzadoverfarenessunaoperazionediconversione.

Avostropiacimentopotetemodificareancheglialtrielementi;perinostriscopi,co-munque,nonsonorichiesteulteriorimodifiche.

Page 35: Manuale IOS

35

c a P I t o l o 2E l e m e n t i P r i n c i p a l i

Colleghiamooraglielementicreatiallaclasse“ViewController”,propriocomeab-biamo fatto nel primo capitolo. Creiamo un outlet per l’image view chiamandola“viewImmagine”.Dobbiamocreareanchetreazioni(sempreeseguendoilcollega-mento e selezionando “Action” dal pop-up che appare): unaper lo slider (“cam-biaAlpha”),unaper ilsegmentedcontrol (“cambiaImmagine”)eunaper ilbottone(“visualizzaAlpha”).

Il codice della vostra classe dovrebbe essere questo:

Codice 2.1: File di interfaccia ViewController.h

123456789

@interface ViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIImageView *immagine;

- (IBAction)cambiaAlpha:(id)sender;- (IBAction)cambiaImmagine:(id)sender;- (IBAction)visualizzaAlpha:(id)sender;

@end

Nota: Perché non abbiamo creato gli outlet anche per lo slider e per il segmented control? Semplice, perché utilizzeremo il parametro “sender” dei rispettivi metodi.

Possiamo ora passare alla scrittura del codice.

Page 36: Manuale IOS

36

Scriviamo il codice necessarioPrimadipoterimplementareimetodi,abbiamobisognodi3immagini,cheverran-no caricate all’interno della nostra image view. Scegliete tre immagini e inseritele nel vostro progetto semplicemente trascinandole al suo interno. Vi apparirà una schermataincuidovreteassicurarvidispuntarel’opzione“Copy items into desti-nation group’s folder (if needed)”.Cliccatesu“Finish”evedretelevostreimmaginiappariretraifiledelprogetto:

Codice 2.2: Implementazione del “viewDidLoad”

1234567

- (void)viewDidLoad { [super viewDidLoad]; // settiamo l’immagine iniziale self.immagine.image = [UIImage imageNamed:@”immagine1.png”]; // impostiamo l’alpha iniziale self.immagine.alpha = 0.5;}

Fig. 2.5: File del progetto

Orapossiamoiniziareascrivereilcodicechegestiscelanostraapplicazione.Apria-moilfile“ViewController.m”einiziamomodificandoilmetodo“viewDidLoad”:

Questometodovienerichiamatoquandolavistaèstatainizializzataestaperapparire.Dobbiamoimpostareun’immagineinizialechevengamostratanellaimageview(riga4).Questaoperazioneviene fattaconuncomodometododellaclasseUIImage,chepermettedispecificareilnomedell’immaginechedeveesserecaricata(l’immagine,ovviamente, deve essere all’interno del progetto).

L’istruzione successiva (riga 6) imposta un valore iniziale della trasparenza (devecoincidereconilvaloreinizialedelloslider).

Oradobbiamodefinire iduemetodichesioccupanodicambiare l’immagineedicambiarnelatrasparenza.

Page 37: Manuale IOS

37

Eccoli:

Codice 2.3: Metodi per la modifica dell’immagine e della sua trasparenza

Codice 2.4: Metodo per la visualizzazione dell’alpha

123456789101112

131415

1

2

- (IBAction)cambiaAlpha:(id)sender { // associamo il sender ad un elemento UISlider UISlider *sliderAlpha = (UISlider*)sender; // modifichiamo il valore alpha dell’immagine self.immagine.alpha = sliderAlpha.value;}

- (IBAction)cambiaImmagine:(id)sender { // associamo il sender ad un elemento UISegmentedControl UISegmentedControl *seg = (UISegmentedControl*)sender; // creiamo il nome dell’immagine da caricare NSString *nomeImmagine = [NSString stringWithFormat:@”immagine%i.png”,seg.selectedSegmentIndex+1]; // carichiamo l’immagine voluta dall’utente self.immagine.image = [UIImage imageNamed:nomeImmagine];}

- (IBAction)visualizzaAlpha:(id)sender { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”Alpha” message:[NSString stringWithFormat:@”Il valore della trasparenza è: %f”,self.immagine.alpha] delegate:nil cancelButtonTitle:@”Ok” otherButtonTitles:nil, nil]; [alert show];}

Inentrambipotetevederecomevieneutilizzatoilparametro“sender”.Primavienefattouncastingversol’oggettochesappiamoessere(righe3e10),poipuòessereutilizzato.Ovviamentequestaoperazionepuòesserefattasenzacontrolliseunparti-colaremetodovienechiamatodaunsolooggetto(comenelnostrocaso).Seinvecepiùoggetti (magarididiversanatura) richiamassero lostessometodo,dovremmoeseguiredeicontrolliprimadipoterdefinireunnuovooggetto.

Ilmetodo“cambiaAlpha:”èdavverosemplice:vieneimpostatalatrasparenza(alpha)dell’immagineponendolaugualealvaloredelloslider(riga5).

Ilmetodo“cambiaImmagine:”,invece,haun’istruzioneinpiù:vienecreataunava-riabile“nomeImmagine”incuisicreailnomedell’immaginedacaricare.Essaèfattasemplicementeinserendoilvaloredell’indicedelsegmentedcontrolselezionatopiùuno(perchèilprimoelementohaindicezero,enonuno)all’internodellastringa“im-magine.png”,propriocomeabbiamovistonelprimocapitolo.Inquestomodovienecreataunastringachecoincidealnomedell’immaginedavisualizzare.Essa,infatti,vienepoicaricataconlastessaistruzioneutilizzatanel“viewDidLoad”(riga14).

Manca ora solo un ultimo metodo:

c a P I t o l o 2E l e m e n t i P r i n c i p a l i

Page 38: Manuale IOS

38

Questovisualizzeràunaclassicaalertviewincuivienemostratounmessaggioconilvaloredell’alphadell’immagine.Comepoteteintuire,cisaràsolounbottoneperchiu-derla(ilcuinomeè“Ok”),mentreilmessaggiovienecreatocomegiàvistopiùvolte(danotarecheinquestocasoabbiamoutilizzato“%f”perinserireunvaloreditipofloatall’internodellastringa).L’istruzioneallariga2,infine,visualizzaaschermol’alertview.Prendetebeneconfidenzaconquestooggetto,inquantoèlamodalitàpiùcomodapercomunicarebreviinformazioniall’utente.

Abbiamocompletatoanchequestaapplicazione!Premete“Run”etestatelavostranuovaapplicazione!

Fig. 2.6a: App 2 “ElementiPrincipali” Fig. 2.6b: App 2 “ElementiPrincipali”

Page 39: Manuale IOS

39

c a P I t o l o 3Tr a s h A p p

3. Gestiamo immagini ed eseguiamo semplici animazioni

Inquestoterzotutorialinizieremoaprendereconfidenzaconunaspettomoltoim-portante:lagestionedelleimmaginiecomel’utentepuòinteragireconesse.Vedre-mo,inoltre,comerealizzaresemplicementedelleanimazioniconquesticomponenti.Andremoacreareunfintocestino,incuipotremotrascinareun’immagineeripristi-narla tramite un apposito pulsante.

Creiamo la struttura graficaCreiamo un nuovo progetto di tipo “Single View Application” e chiamiamolo“TrashApp”.Comesempreassicuriamociche“Usestoryboard”e“IncludeUnitTest”siano disattivati. Primadifarequalsiasicosa,inseriamonelnostroprogettoleimmaginicheciservi-ranno.Ioutilizzeròleseguentiimmagini:dueperilcestino,eunaperildocumentoda“eliminare”(potetetrovarequesteimmagininelfilediprogettodell’esempio):

Fig. 3.1a: Windows icon.png Fig. 3.1b: TrashIconEmpty.png Fig. 3.1c: TrashIconFull.png

TrascinateleimmagininelprogettoinXCode,enelpop-upcheviappariràmettetelaspuntaa“Copy items into destination group’s folder (if needed)”(comeabbiamofatto nel precedente tutorial).Apriamoquindiilfile“ViewController.xib”einiziamoadefinirelanostrainterfaccia.Inseriamo, per prima cosa, gli elementi necessari: due componenti UIImageView e un UIButton.

Fig. 3.2: Interdaccia di “TrashApp”

Page 40: Manuale IOS

40

Dobbiamooraconfigurareleproprietàdelledueimageview.

Selezioniamoquella inaltoeandiamoin“AttributesInspector”:nelmenùatendi-na“Image”selezioniamoilfile“windows icon.png”elovedremocomparireanchenell’applicazione.Selezioniamo“Center”in“Mode”espuntiamoinoltrelacasella“User Interaction Enabled”.

Avremo un pannello così impostato:

Fig. 3.4: Interdaccia di “TrashApp” m

odificata

Fig. 3.3: Proprietà delle im

age view

Insostanzaabbiamoselezionatoquel-ladeterminataimmaginechedevees-serevisualizzatanellaimageview,ab-biamoimpostatochel’immaginesiaalcentrodell’oggettoeche sia abilitatal’interazioneconl’utente.

Facciamo la stessa cosa per l’image view sottostante, selezionando comeimmagine“TrashIconEmpty.png”; “Center”in“Mode”masenzaspuntare“UserInteractionEnabled”.

Inseriamo all’interno del bottone la scritta“Ripristinalogo”.

Aggiustiamoledimensionielaposizio-nedelledueimmagini(inmodocheibordi delle image view coincidano con le immagini al loro interno) fino ad ave-re un risultato come quello proposto di seguito(figura3.4).

Page 41: Manuale IOS

41

Dobbiamooracreareglielementinellaclasse“ViewController”,comeabbiamogiàfattoneiprecedenticapitoli.Creiamounoutletperledueimageview,chiamandolerispettivamente“imageLogo”e“imageCestino”.Dobbiamocreareancheun’azioneperilbottone(sempreeseguendoilcollegamentoeselezionando“Action”dalpop-upcheappare”),chechiameremo“ripristinaLogo”.

Lavostraclasse“ViewController.h”saràquindicosìdefinita:

Codice 3.1: File di interfaccia ViewController.h

12345678

@interface ViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIImageView *imageLogo;@property (strong, nonatomic) IBOutlet UIImageView *imageCestino;

- (IBAction)ripristinaLogo:(id)sender;

@end

Siamoprontiperscrivereilcodiceveroeproprio!

Implementiamo il movimento del logoIniziamoinserendounavariabileeunmetodocheciservirannosuccessivamente.

Definiamolinelfile“ViewController.h”:

Codice 3.2: Definizione degli elementi necessari

123456789101112

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController { BOOL cancellato;}

@property (strong, nonatomic) IBOutlet UIImageView *imageLogo;@property (strong, nonatomic) IBOutlet UIImageView *imageCestino;

- (IBAction)ripristinaLogo:(id)sender;

@end

Allariga4abbiamodefinitounavariabilebooleana(ovveropuòassumeresoloduevalori:YESoNO),checiserviràpercontrollareseillogodiWindowsègiàstatoeli-minato.

Quindi, al valore YES corrisponderà il logo eliminato, a NO il logo sarà ancora visibile.

c a P I t o l o 3Tr a s h A p p

Page 42: Manuale IOS

42

Orainiziamoadimplementareimetodinecessari. Apriamoilfile“TrashAppViewController.m”einseriamoilseguentecodice:

Codice 3.3: Implementazione dei vari metodi

1234567891011121314

1516171819202122

232425262728

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { // ricaviamo i tocchi fatti dall’utente UITouch *touch = [[event allTouches] anyObject]; // controlliamo che il tocco sia stato sull’oggetto del logo if ([touch view] == imageLogo) { imageLogo.center = [touch locationInView:self.view]; }}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // controlliamo se il logo interseca il cestino if (CGRectIntersectsRect([imageLogo frame], [imageCestino frame])) { // cambiamo l’immagine del cestino imageCestino.image = [UIImage imageNamed:@”TrashIconFull.png”]; cancellato = YES; // eseguiamo l’animazione per far sparire il logo [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.5]; imageLogo.transform = CGAffineTransformMakeScale(.001, .001); [UIView commitAnimations]; } else { // il logo non interseca il cestino, riportiamolo alla po-sizione iniziale [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.5]; imageLogo.center = CGPointMake(158.0, 147.0); [UIView commitAnimations]; }}

Ilmetodo“touchesMoved:withEvent”èunmetodoereditatodallaclasseUIRespon-der,cheogniclasseeredita.Talemetodovienerichiamatoquandol’utenteiniziaunmovimento sulla vista. Perprimacosasalviamonellavariabile“touch”glieventichel’utentecompietoc-candounqualsiasioggettodellanostraapplicazione(riga3).Controlliamo,poi,chel’oggettotoccatocorrispondaa“imageLogo”(riga5),cioèallogodiWindows:sel’oggettoèproprioquello,teniamotracciadelcentrodell’ogget-to(chenelfrattempovienemossodall’utente)conlaposizionedelditosulloschermo(riga6).Ovvero,ècomesespostassimofisicamentel’oggettoconilnostroditoelomuovessimo su un piano.

Ilsecondometodo,“touchesEnded:withEvent:”,vienerichiamatoquandoilmovimentotermina,ovveroquandol’utenterilasciailditodalloschermodell’iPhone.Quidobbiamocontrollaresel’utentehatrascinatoillogonelcestino.Perfareciòcontrolliamoseilfra-medi“imageLogo”(ovveroillogodiWindows)intersecailframedelcestino(riga12).

Page 43: Manuale IOS

43

Incasopositivocambiamol’immaginedelcestino(riga14),settiamolavariabile“can-cellato” aYES ed eseguiamo l’animazione per far sparire il cestino (dalla riga 16). Leanimazionivengonoeseguitetramitele“UIAnimation”,disponibiliinUIView.Ilme-todo“beginAnimation:context:”(riga17)èilpuntodiiniziodell’animazione,conclu-socon“commitAnimations”(riga20).All’internodiquestedueistruzionipossiamospecificarequalsiasicomportamentochedeveessereeseguitosuglioggetti.Nelno-strocasosemplicementetrasformiamol’oggettorendendolopiccolissimo(riga19),inmodochesia“nascosto”.Ilcontrollosull’intersezione,però,potrebbeancheavereesitonegativo(riga21):intalcasoeseguiamoun’altraanimazione,riportandoillogodiWindowsalsuostatoiniziale(riga25).

Cimancasolol’implementazionedelmetodo“ripristinaLogo:”,associatoallapres-sionedelbottone.L’intestazionedelmetodoègiàstatadefinitadaXcode(lotrove-reteprobabilmenteallafinedi“ViewController.m”).

Eccolasuaimplementazione:

Codice 3.4: Implementazione di “ripristinaLogo:”

12345

6789

10111213

- (IBAction)ripristinaLogo:(id)sender { // controlliamo se il logo è stato eliminato if (cancellato) { cancellato = NO; // riportiamo il logo in posizione iniziale e svuotiamo il cestino [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.5]; imageLogo.transform = CGAffineTransformIdentity; imageCestino.image = [UIImage imageNamed:@”TrashIconEmpty.png”]; imageLogo.center = CGPointMake(158.0, 147.0); [UIView commitAnimations]; }}

Inquestometodoperprimacosacontrolliamoseillogoèstatocancellato(riga3):seilcontrollodaesitopositivo,settiamolavariabile“cancellato”a“NO”(riga4).Fattociòeseguiamol’animazioneperripristinareillogoesvuotareilcestino.Taleanima-zioneèdeltuttosimileallaprecedente,maeseguesolamentel’azionecontraria!

Abbiamoconcluso!Cliccatesu“Run”etestatelavostranuovaapplicazione!

c a P I t o l o 3Tr a s h A p p

Page 44: Manuale IOS

44

Fig. 4.5b: App 3 “TrashApp”Fig. 4.5a: App 3 “TrashApp”

Page 45: Manuale IOS

45

c a P I t o l o 4M u l t i B ro w s e r

4. MultiBrowser: creiamo un browser

Inquestocapitolovedremoun’aspettofondamentalenellacreazionediun’applica-zione,ovvero lagestionedipiùviste. Intutte leapplicazioni, infatti,sonopresentidiverseviste (“finestre”,perusareun terminepiùgenerico), chevengonospessocreateconInterfaceBuilder(equindidiversifile“.xib”)datalasuacomodità.Utilizzeremo,inoltre,uncomponentemoltocomodoepotente:leUIWebView,ovverodeglioggettichepermettonodicaricaredellepagineweb.

Creeremounasortadibrowser,incuicisaràunavistaprincipalecondeibottonicherimanderanno a determinate pagine web. Tali pagine verranno mostrate su un’altra finestracheverràapertaappositamente.Èimportanteseguirebenetuttiipassaggi,inmodochepossiatereplicarelastessastrutturaanchenellevostreapplicazionipiùcomplesse,senzaerroriesenzaperderetempoprezioso.

Creiamo la struttura graficaCreiamounnuovoprogettoditipo“SingleViewApplication”echiamiamolo“Multi-Browser”.Comesempreassicuriamociche“Use storyboard”e“Include Unit Test”siano disattivati.

Iniziamocreandolasemplicestrutturadellaprimavista.Apriamoquindiilfile“ViewCon-troller.xib”einseriamoduebottoni:

Fig. 4.1: Pulsanti per “M

ultiBrosw

er”

Page 46: Manuale IOS

46

Dobbiamooracollegareibottoniallaclassecreandoleazionicorrispondenti,comeabbiamo più volte fatto. Abbiamo tre strade diverse percorribili:•Crearedueazionidistinteperognibottone,maquestaèlasoluzionepeggiore.

•Definiredueelementi(outlet)eunasolaazione,identificandopoiilbottonechehainvocatol’azioneinbasealsender(comeabbiamofattoneltutorialprecedente).

•Oppurec’èunaterzatecnica,checonsistenell’utilizzarelaproprietà“tag”.Questaèun’attributo (omeglio,unaproprietà)chequalsiasioggettodiUIKitpossiede,edèsemplicementeunvalorenumericocheloidentifica.Talevaloreperdefaultèzero,maassegnandovaloridiversiperognielementosaremoingradodidistin-guerli in maniera univoca.

Selezioniamo il primobottone e apriamo l’“Attributes Inspector”. Tra i vari campipresentinoteremoquellorelativoa“Tag”.Modifichiamoneilvalorea1:

Fig. 4.2: Attributes Inspector dei bottoni

Quindiilbottone“BubiDevs”avràlaproprietàtagimpostataa1.Facciamolastessacosa con il secondo bottone, ma impostando il tag a 2.Fattociònondobbiamofaraltrochecreareun’azionecherispondaallapressionedeiduebottoni.Comealsolito,creiamoun’azionepartendodalprimobottone(sem-preeseguendoilcollegamentoeselezionando“Action”dalpop-upcheappare),chechiameremo“apriSito”.Lavostraclasse“ViewController.h”saràquindicosìdefinita:

Codice 4.1: File di interfaccia ViewController.h”

1234567

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

- (IBAction)apriSito:(id)sender;

@end

Page 47: Manuale IOS

47

Oradobbiamocollegare lastessaazioneancheall’altropulsante.Semprenelfile“ViewControlle.xib”selezionate il “File’sOwner”espostatevinel“Connections In-spector”.Avreteunpannellocosìcomposto:

Fig. 4.3: Connections Inspector del File’s Owner

Fig. 4.4: Collegamento eseguito correttamente

Prendiamoilpallinochetrovateadestradellascritta“Button-BubiDevs”etrascinia-molosulsecondobottone,selezionandopoi“Touch Up Inside”nelmenùatendinachesipresenta.Se avete eseguito correttamente il passaggio avrete il seguente risultato:

Abbiamocosìcollegatolastessaazioneanchealsecondobottone.Questoèilpro-cedimentochedeveessereeseguitoquandosicreaun’azione (ounoggetto)viacodice e lo si vuole poi collegare con un oggetto creato in IB.

c a P I t o l o 4M u l t i B ro w s e r

Page 48: Manuale IOS

48

Creiamo la seconda vistaPrima di proseguire nell’implementazione della prima vista, creiamo la seconda.EssaconterràunasempliceUIWebView,chevisualizzeràlapaginawebasecondadel bottone premuto dall’utente.InXcode,scegliamo“File->NewFile...”eciappariràlaseguenteschermata:

Fig. 4.5: Creiamo il file per la seconda vista

Scegliamo“UIViewController”cometipologiadiclasse,inseriamo“BrowserViewCon-troller”comenomeeassicuriamocichesiaspuntatal’opzione“With XIB for user in-terface”.Nellaschermatasuccessivapremiamo“Create”.Abbiamocosìcreatounanuovavista,comprensivasiadiinterfacciagraficachedirelativaclasse.Apriamoilfile“BrowserViewController.xib”permodificarel’interfacciagraficacomenell’immaginepropostanellapaginasuccessiva(Fig.4.6).

Page 49: Manuale IOS

49

Ilcomponentewebviewèquellochevisualizzeràlapaginawebdesiderata,edoc-cupa la maggior parte della vista. Nella parte bassa, invece, abbiamo inserito un componente di tipo UIToolbar e tre bottoni UIBarButtonItem, separando gli ultimi duetramiteun“Flexible Space Bar Button Item”.Questoèunelementochepermet-tediavereibottoniaidueestremidellatoolbar,senzadovercioccuparediimpostaredelle posizioni assolute. Tale componente, inoltre,mantiene i bottoni agli estremianchesel’interfacciavieneruotata.Iprimiduebottoniciservirannopermuovercitralepaginevisitate(iclassici“Avanti”e“Indietro”),mentreilterzoserviràpertornareallaschermataprincipale.Iniziamoimplementandoleazioniperibottoni“Avanti”e“Indietro”.Inquestocasonondovremofarepraticamentenulla,sioccupadituttolaUIWebView.Selezionatelaespostatevinel“ConnectionsInspector”:

Fig. 4.6: Struttura di B

rowserV

iewC

ontroller.xib

Fig. 4.7: Connessioni della UIWebView

c a P I t o l o 4M u l t i B ro w s e r

Page 50: Manuale IOS

50

Comevedetesonogiàpresentivarieazioni.Collegate“goBack”conilbottone“<“(ovveroquellopertornareallapaginaprecedente”,e“goForward”conilbottone“>”.

Fig. 4.8: Connessioni per i bottoni “avanti” e “indietro”

Fatto!Questeazioniverrannoimplementateautomaticamentedallawebview,senzadoverscrivereunarigadicodice!

Cisonoancheduealtreazioni,cheservonoperricaricarelapaginaoperfermarneil caricamento. Noi non le abbiamo implementate, ma se volete creare un browser ancorapiùcompletonullavivietadiutilizzarle.

Fatto ciòdobbiamodefinire nella classeunoggettoper laweb vieweun’azionecollegataalbottone “Home”.Comesempre facciamociòcollegandogli elementidell’interfaccia con la classe.

Createquindiunoutletperlawebviewechiamatela“webView”,eun’azioneasso-ciataalbottonechiamata“tornaAdHome”.Seaveteeseguitotuttocorrettamentelavostraclasse“BrowserViewController.h”saràcosìcomposta:

Codice 4.2: File di interfaccia BrowserViewController.h

123456789

#import <UIKit/UIKit.h>

@interface BrowserViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIWebView *webView;

- (IBAction)tornaAdHome:(id)sender;

@end

Page 51: Manuale IOS

51

Scriviamo il codice per aprire la pagina desiderataPrimadiproseguire,dobbiamodefinireunavariabile (con la relativaproperty)checonterràl’indirizzowebdellapaginadavisualizzare.Questavariabileverràimpostatadalla prima vista in base al bottone premuto dall’utente. Nelfile“BrowserViewController.h”inseriamoleseguentidichiarazioni:

Codice 4.3: Stringa dell’indirizzo web

Codice 4.4: Caricamento della pagina web

123456789101112

123456789101112

#import <UIKit/UIKit.h>

@interface BrowserViewController : UIViewController { NSString *indirizzo;}

@property (strong, nonatomic) NSString *indirizzo;@property (strong, nonatomic) IBOutlet UIWebView *webView;

- (IBAction)tornaAdHome:(id)sender;

@end

@synthesize webView;@synthesize indirizzo;

- (void)viewWillAppear:(BOOL)animated{ // creiamo un oggetto NSURL con l’indirizzo della pagina da caricare NSURL *url = [NSURL URLWithString:indirizzo]; // creiamo una richiesta per la pagina NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // visualizziamo la richiesta (la pagina) nella web view [webView loadRequest:request];}

Semplicemente abbiamodefinito una variabile di tipo stringa (riga 4) e la relativaproperty(riga7).Dobbiamoorainserireilcodicechesioccupadicaricarelapaginawebselezionatadall’utenteemostrarlanellaUIWebView.Utilizziamounmetodochevienerichiamatoquando la vista sta per apparire. Ecco il codice da inserire:

Allariga2abbiamoinseritoil“synthesize”necessarioperlapropertycheabbiamoprecedentementedefinito.Ilmetodo“viewWillAppear:”vienerichiamatoquandolavistastaperesserevisualizzata:èlicheinizializziamoglielementinecessaripervi-sualizzarelapaginawebdesiderata.Davvero semplice e veloce.

c a P I t o l o 4M u l t i B ro w s e r

Page 52: Manuale IOS

52

Gestiamo il passaggio tra le due visteOra ci manca solo la gestione del passaggio tra le due viste. Per prima cosa ci occu-piamo del codice necessario per passare dalla prima vista alla seconda. Dovremo leggere quale bottone è stato premuto (controllando la proprietà tag) epassare l’indirizzocorrettoallasecondavista.Apriamo il file “ViewController.m”eandiamoadefinireilmetodo“apriSito:”:

Codice 4.5: Passaggio dalla prima alla seconda vista

1234

5

67891011121314

- (IBAction)apriSito:(id)sender{ UIButton *bottone = (UIButton*)sender; BrowserViewController *viewBrowser = [[BrowserViewController alloc] initWithNibName:@”BrowserViewController” bundle:nil]; viewBrowser.modalTransitionStyle = UIModalTransitionStyle-FlipHorizontal; if (bottone.tag == 1) { viewBrowser.indirizzo = @”http://www.bubidevs.net”; } else if (bottone.tag == 2){ viewBrowser.indirizzo = @”http://www.google.it”; } [self presentModalViewController:viewBrowser animated:YES];}

PerprimacosaabbiamoconvertitoilsenderinunoggettoditipoUIButton(comeabbiamo già fatto nel precedente capitolo), per poterne leggere la proprietà tag.

Allariga4abbiamoinizializzatolavista,inserendoancheilnomedelfile“.xib”chedeve essere caricato.

L’istruzioneallariga5,invece,cipermettediimpostarel’animazionedelpassaggiodallaprimaallasecondavista.Cisonotreanimazionigiàpredisposteedisponibili:•UIModalTransitionStyleCoverVertical, il caricamento della nuova vista sarà vertica-le,dalbassoversol’alto;

•UIModalTransitionStyleFlipHorizontal,c’èlarotazioneflip-side,ovverocomeseve-nissemostratoilretrodellavista;

•UIModalTransitionStyleCrossDissolve,dissolvenzaincrociata.

Troviamopoiun“if”chesettalavariabile“indirizzo”(lapropertycheabbiamodefi-nito nella classe BrowserViewController) a seconda del bottone premuto dall’utente. Potetevederecheciòvienefattocontrollandolaproprietàtag(righe7e9),propriocome avevamo detto.

L’ultimaistruzione(riga13)permettedimostrarelasecondavista,rendendolacosìvisibile all’utente.

Page 53: Manuale IOS

53

Dopoaverinseritoquestocodice,viverràsegnalatounerroreallariga4(eanchealle successive). Questo avviene perché non c’è nessun riferimento alla classeBrowserViewController. Per correggere questo problema dobbiamo eseguire l’im-portazionedi taleclasse:semplicemente inseritequestadefinizioneall’iniziodelfile“ViewController.m”(sololariga2,lealtresonogiàpresenti):

Codice 4.6: Importiamo la classe BrowserViewController

Codice 4.7: Tornare alla prima vista

1234

123

#import “ViewController.h”#import “BrowserViewController.h”

@implementation ViewController

- (IBAction)tornaAdHome:(id)sender { [self dismissModalViewControllerAnimated:YES];}

Abbiamo quasi concluso! Non ci resta che definire ilmetodo che ci permetta ditornareallaprimavista.Apriamoilfile“BrowserViewController.m”emodifichiamoilmetodo“tornaAdHome:”

Questaunicaistruzionecipermettediusciredallavistacorrenteetornareaquellacheeravisualizzataprecedentemente(nelnostrocasolavista“ViewController”).

Abbiamoconcluso!Clicchiamosu“Run”etestiamoilnostromultibrowser!

c a P I t o l o 4M u l t i B ro w s e r

Page 54: Manuale IOS

54

Fig. 4.8b: App 4 “MultiBrowser”Fig. 4.8a: App 4 “MultiBrowser”

Page 55: Manuale IOS

55

c a P I t o l o 5Ta b l e V i e w Tu t o r i a l

5. UITableView: le tabelle

Ilcomponentepiùutilizzatonellosviluppodiapplicazionièsicuramentequellochegestisce le tabelle, ovvero laUITableView. Inmoltissimeapplicazioni, infatti, essevengonoutilizzatepermostraredelleinformazioniall’utente,chepuòancheintera-gire con questi dati.Inquestocapitolovedremocomedefinireunatabella,comeinserirealsuointernodeivaloriedefiniredeicomportamenti(adesempiolacancellazionedellerighe),necessariperrenderlautilizzabiledall’utente.Questocapitolosaràsuddivisointreparti:•Creazioneedefinizionedellatabella.

•Inserimentodialcunefunzionalità.

•Implementazionedellaricerca.Analizzeremoquestepartiunaallavolta,passoperpasso,inmododacomprenderebeneognisingolopassaggiocheandremoarealizzare.

Parte 1: Creiamo e definiamo la tabella

Laprimapartediquestotutorialèdedicataallacreazionedellastrutturadell’applica-zione:nedefiniremolagrafica,lalistadeglielementidavisualizzareecomemostrarliall’interno della tabella. Il tutto sarà fatto con la solita semplicità, sfruttando tutte le ca-ratteristichecheXcodeel’SDKcimettonoadisposizione,semplificandoilnostrolavoro.

Creiamo la strutturaCreiamounnuovoprogettoditipo“MasterDetailApplication”echiamiamolo“Ta-bleViewTutorial”.Comesempreassicuriamociche“Usestoryboard”e“IncludeUnitTest”sianodisattivati.QuestotemplatediXcodeciforniscegiàunatabellaelarelativaclassechelogesti-sce(“MasterViewController”).Aprendoilfile“MasterViewController.xib”visualizzere-telatabellagiàdefinitapervoi:

Fig. 5.1: MasterViewController.xib

Page 56: Manuale IOS

56

Unatabellahadueelementifondamentali:il“dataSource”eil“delegate”.Seesaminate leconnessionidellatabellanoteretecheentrambequesteproprietàsonocollegateallaclasse“MasterViewController”,chelegestisce.Macosasono?•IldataSource, come dice il nome stesso, è la sorgente dei dati, e deve essere col-legatoconlaclassecheconterràidaticheandrannopoivisualizzatinellatabella.

•Ildelegate,invece,indicachirispondealdelegatodellatabella.Comevedremopoiessoforniscedeimetodimoltoutili,chefacilitano,adesempio,lamodificadellatabella da parte dell’utente.

Quandocreateunatabelladoveteassicurarvicheentrambeleproprietàsianocolle-gate con la classe preposta alla gestione della tabella.

Scriviamo il codice necessarioIniziamoaprendoilfile“MasterViewController.h”,edefiniamoilseguentecomponente:

Codice 5.1: Definizione della lista per il data source

Codice 5.2: Implementazione del “viewDidLoad”

1234567891011

12345678

9

#import <UIKit/UIKit.h>

@class DetailViewController;

@interface MasterViewController : UITableViewController { NSMutableArray *lista;}

@property (strong, nonatomic) DetailViewController *detailViewController;

@end

- (void)viewDidLoad { [super viewDidLoad]; // settiamo il titolo della vista self.title = @”Prodotti Apple”; // elementi della tabella lista = [[NSMutableArray alloc] initWithObjects: @”iPho-ne”, @”iPod”,@”iPod Touch”,@”iPad”,@”iMac”, @”iBook”, @”MacBook”, @”MacBook Pro”, @”Mac Pro”, @”PowerBook”, nil]; }

Abbiamodichiaratounarrayallariga6,checonterràglielementicheandremopoiavisualizzarenellatabella.L’elementoèditipo“mutable”,inquantoavremolaneces-sitàdimodificarneilcontenuto(adesempioquandol’utenteeliminaunariga).Notate,inoltre,cheèpresenteancheunoggettodellaclasse“DetailViewController”,cheèfornitodaltemplatediXcode.Taleclassepuòessereutilizzatapervisualizzarei dettagli di un oggetto, come vedremo più avanti.Spostiamocioranelfile“MasterViewController.m”.Iniziamoinserendoalcuneistru-zionichedevonoessereeseguitealcaricamentodellaclasse:

Page 57: Manuale IOS

57

Abbiamosemplicementedefinitoduecosemoltosemplici.Allariga5abbiamoimpo-statoiltitoloallanavigationbar(questoèpossibilesoloquandosilavoraconquestotipoditemplate,cheèdefinitopartendodaunnavigationcontroller),mentreallariga8abbiamoinizializzatol’arrayconalcunielementi,cheandrannopoivisualizzatinellanostra tabella.

Oradobbiamodefinireimetodichesioccupanodipopolarelatabella.Scorrendoilfile“MasterViewController.m”litroveretegià(Xcodeliinserisceautomaticamentequandosiutilizzaquestotipoditemplate),dobbiamosolocompletarli.Iniziamodefinendoiseguentiduemetodi:

Codice 5.3: Metodi per la definizione della tabella

123456

78

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1;}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [lista count];}

Ilprimocheincontriamoè“numberOfSectionsInTableView:”.Seprovateamodificarequestovalore,vedreteche (quandoeseguirete l’applicazione) la listadeglioggettisaràripetutapiùvolte.Provarepercredere!Acosaserve?Nelcasoincuivogliatecreareunatabellasuddivisainpiùsezioni,adesempiocomequelladell’applicazionenativa“Contatti”,chesuddivideglielementiinordinealfabetico.Nelnostrocaso,adesempio,avremmopotutocrearedellediversesezionipericomputerportatilieperquellifissi.

Ilsecondometodoè“tableView: numberOfRowsInSection:”esettailnumerodicelleinognisezione(nelnostroesempioavremounasolasezione).Questovaloredevecorrisponderealnumerodielementichevogliamoinserirenellatabella,quindiquellicontenutinell’oggetto“lista”.

Dobbiamooradefinireilmetodochesioccupadiimpostarelevariecellechecom-pongonolatabella.Nellapaginasuccessivatrovereteilmetodoinquestione(anchequesto lo trovate già nella vostra classe).

c a P I t o l o 5Ta b l e V i e w Tu t o r i a l

Page 58: Manuale IOS

58

Questoè ilmetodo (fondamentaleedobbligatorio)chesioccupadi impostare inmaniera corretta le celle della tabella.

Allariga4troviamoladichiarazionediunacella,chevienepoiinizializzataallariga6.

Alla riga 10 settiamo il valore contenuto nella cella: esso deve essere letto dall’array, nellaposizioneugualeaquelladellariga(ricordatevichesialanumerazionedell’ar-raychedellecellepartedazero).

Inquestocasoabbiamoimpostatounacellamoltosemplice,checontienesolounvalorealsuointerno(impostatoappuntotramitelaproprietà“textLabel”).Questostiledicellaè“UITableViewCellStyleDefault”,comepossiamovederenell’i-struzioneallariga6.Ilrisultatosaràilseguente:

Codice 5.4: Definizione delle celle

1

234

56

789101112

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @”Cell”; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; }

// Configure the cell. cell.textLabel.text = [lista objectAtIndex:indexPath.row]; return cell;}

Fig. 5.2a: UITableViewCellStyleDefault

Page 59: Manuale IOS

59

Sonodisponibili,però,anchealtri stilidi cellecheovviamentepoteteutilizzare inbaseallevostreesigenze.Eccoveli:

•UITableViewCellStyleSubtitle:

Fig. 5.2b: UITableViewCellStyleSubtitle

Fig. 5.2c.: UITableViewCellStyleValue1

Fig. 5.2d: UITableViewCellStyleValue2

•UITableViewCellStyleValue1:

•UITableViewCellStyleValue2,

In questi diversi stili di cella potete accedere al secondo campo di testa tramite la proprietà“detailTextLabel”,propriocomeavvieneper“textLabel”.Quindi,perotte-nere un risultato come quello mostrato dovrete inserire il seguente codice:

Codice 5.5: Utilizzo della proprietà “detailTextLabel”

123

// Configure the cell.cell.textLabel.text = [lista objectAtIndex:indexPath.row];cell.detailTextLabel.text = @”Apple”;

c a P I t o l o 5Ta b l e V i e w Tu t o r i a l

Page 60: Manuale IOS

60

Sieteprontipertestarelavostratabella!

Cliccatesu“Run”econtrollatechetuttofunzioni!

Fig. 5.3a: App 5 Beta “TableViewTutorial”

Page 61: Manuale IOS

61

Parte 2: Inseriamo alcune funzionalità

Abbiamofinoadoravistoqualisonoipassifondamentaliperdefinireunatabella.Inquestasecondaparteaggiungeremoalcunefunzioni,adesempiolapossibilitàdieliminareunadeterminatariga.Analizzeremo,inoltre,comevienegestitalaselezionee l’apertura della vista di dettaglio.

Permettiamo la cancellazione di una rigaLaprimacosadafareèinserireilbottonechepermettediaccedereallamodificadellatabella.Perfareciòcibastainserireunasempliceistruzioneenelmetodo“viewDidLoad”:

Codice 5.6: Permettiamo la cnacellazione di una riga

123

101112

- (void)viewDidLoad { [super viewDidLoad]; ... // permettiamo la modifica di una cella self.navigationItem.rightBarButtonItem = self.editButtonItem;}

Semplicementeassociamoalbottonedestrodellanavigationbarilbottonecheabi-litalamodificadell’elemento.Ancheinquestocasoètuttomoltosemplice,graziealle API fornite da Apple.

Seprovateadeseguirel’applicazionenoteretechecancellandounarigaessanonvienerimossadallatabella.Questoavvieneperchénonabbiamoancoraimplemen-tato il codice vero e proprio per eliminare un elemento della tabella. Scorreteilvostrofile“MasterViewController.m”ecercateilmetodo“tableView: com-mitEditingStyle: forRowAtIndexPath:”,chetroveretecommentato.Decommentateloeinseritel’istruzioneallariga5:

Codice 5.7: Cancellazione di un elemento

12

34567

89

1011

// Override to support editing the table view.- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // eliminiamo l’elemento dalla lista [lista removeObjectAtIndex:indexPath.row]; // eliminiamo la cella dalla tabella [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. } }

c a P I t o l o 5Ta b l e V i e w Tu t o r i a l

Page 62: Manuale IOS

62

Come possiamo notare dalla struttura un po’ complicata, questo è un metodo del protocolloUITableView.Ilcostrutto“if”(riga3)controllaseiltipodiazioneeseguitasullatabellaèlacancellazionediunariga.Diretevoi,cos’altroposso fare?Peroraniente,perché lanostra tabellasupportasolol’eliminazionediunariga,mavolendosipotrebbeimplementareanchel’inseri-mentodiunanuovariga(edèilcontrolloallariga8),oppurealtreazioni.Èsemprequestometodochesioccupadigestiretutteleazionisullatabella.

Eccospiegatalanecessitàdiquestocontrollo.Tornandoalcodice,all’internodell’“if”possiamonotaredueistruzioni,cheeliminanol’elementosiadallalista(riga5)chedal-latabella(riga9).Inquestomodolacancellazionediunarigaèdavveroimplementata.

Codice 5.8: Metodo che gestisce la selezione di una cella

1234

567

89

10

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (!self.detailViewController) { self.detailViewController = [[DetailViewController alloc] initWithNibName:@”DetailViewController” bundle:nil]; } // passiamo l’oggetto selezionato self.detailViewController.detailItem = [lista objectAtIndex:indexPath.row]; // apriamo la vista [self.navigationController pushViewController:self.detail-ViewController animated:YES];}

Nota: Fate attenzione a rimuovere prima l’elemento dalla lista e poi dalla tabella: invertendo queste due istruzioni otterreste un crash della vostra applicazione!

La vista di dettaglioVisareteprobabilmentegiàaccorticheiltemplatechestiamoutilizzandoforniscegiàun’implementazioneperlavistadidettagliodiognicella.Essaèunavistagene-rica,chevieneapertaeconfigurataasecondadell’elementoselezionatodall’utente.Seprovateaselezionareunqualsiasielemento,infatti,verràapertalastessavistadidettaglio,cheperòmostrasemprelostessomessaggio.VediamooracomeèstataimplementatadaAppleecomemodificarlaperrenderlaadattaainostriscopi.

Quandol’utenteselezionaunacellavienerichiamatoilseguentemetodo(chetrovategiàdefinitonellaclasse“MasterViewController.m”):

Ilmetodoègiàfunzionante,dovetesolo inserire l’istruzioneallariga7,chepassal’oggetto selezionato (in pratica solo una stringa con il nomedel prodotto sceltodall’utente) alla vista di dettaglio.

Page 63: Manuale IOS

63

Questometodoprima inizializza la vista di dettaglio (se essa non è ancora statainizializzata),poilavisualizza.Noteretechel’istruzionepervisualizzarelavistaèdi-versadaquellautilizzatanelcapitoloprecedente:questoperchéstiamolavorandoinunnavigationcontroller,chehauncomportamentodiversorispettoallastrutturaprecedente.L’istruzione,comunque,èanch’essasempliceeimmediata.

Praticamenteabbiamogiàconcluso!Grazieadunasolaistruzionelavistadidetta-gliomostreràalcentroilnomedell’elementoselezionatodall’utente.

Poteteovviamentemodificareavostropiacimentolaclasse“DetailViewController”,chegestisceappuntolavistadidettaglio.

Fig. 5.3c: App 5 Beta “TableViewTutorial”Fig. 5.3b: App 5 Beta “TableViewTutorial”

c a P I t o l o 5Ta b l e V i e w Tu t o r i a l

Page 64: Manuale IOS

64

Parte 3: Implementiamo la ricerca

Nella terza e ultima parte di questo lungo tutorial dedicato alle tabelle, vedremocome aggiungere un box di ricerca. Il comportamento sarà del tutto simile a quello dellaricercapresentenell’applicazionenativa“Contatti”.Vedretechequestaoperazionesiriveleràmoltosemplice,infattiApplehalavoratomoltosuquestoaspettoconleultimeversionidelSDK.

Aggiungiamo il box di ricercaApriamoilfile“MasterViewController.xib”permodificarlo:dovremoinserirelanostrabarradiricerca.Dalla“Library”selezioniamouncomponente“SearchBarandSe-archDisplayController”,etrasciniamolosopral’elemento“TableView”,comemo-strato nella seguente immagine:

Fig. 5.4: Inseriamo la barra di ricerca “Search Bar and Search Display Controller”

Page 65: Manuale IOS

65

Seaveteeseguitotuttocorrettamentelavostratabellamostreràoraancheunabarradi ricerca:

Fig. 5.5: Barra di ricerca

Abbiamoconclusolapartegrafica,possiamooradedicarcialcodice!

Modifichiamo i metodi già esistentiPrimadiimplementarelaricercaveraepropria,dobbiamofaredellepiccolemodifi-cheaimetodigiàpresentinelnostroprogetto.

Dobbiamo,perprimacosa,definireunanuovalista,checonterràglielementi“filtrati”,ovveroquellichecorrisponderannoaicriteridiricerca.

Apriamoilfile“MasterViewController.h”einseriamolaseguentedefinizione(riga7):

Codice 5.9: Lista per gli elementi filtrati

12345678910

1112

#import <UIKit/UIKit.h>

@class DetailViewController;

@interface MasterViewController : UITableViewController { NSMutableArray *lista; NSMutableArray *listaFiltrata;}

@property (strong, nonatomic) DetailViewController *detailViewCon-troller;

@end

c a P I t o l o 5Ta b l e V i e w Tu t o r i a l

Page 66: Manuale IOS

66

Oradobbiamomodificare ilmetodo “viewDidLoad”, inmodoche inizializzi anchequesta nuova lista. Spostiamociin“MasterViewController.m”emodifichiamotalemetodo:

Codice 5.10: Inizializzazione della nuova lista

12345678

9101112131415

- (void)viewDidLoad { [super viewDidLoad]; // settiamo il titolo della vista self.title = @”Prodotti Apple”; // elementi della tabella lista = [[NSMutableArray alloc] initWithObjects: @”iPho-ne”, @”iPod”,@”iPod Touch”,@”iPad”,@”iMac”, @”iBook”, @”MacBook”, @”MacBook Pro”, @”Mac Pro”, @”PowerBook”, nil]; // elementi per la lista filtrata listaFiltrata = [[NSMutableArray alloc] initWithArray:lista]; // permettiamo la modifica di una cella self.navigationItem.rightBarButtonItem = self.editButtonItem;}

Semplicementeabbiamoaggiuntol’istruzioneallariga11,cheinizializzalalistafiltrataconglistessielementidi“lista”. Inizialmentequesta listasaràugualealla listadeglielementi,everràmodificatamanmanochel’utenteinserisceiltestodaricercare.Questa lista, ora, sarà il nuovo dataSource, infatti la tabella verrà popolata in base al contenutodellalistafiltrata,mentrel’altralistaserviràsoloperripristinarelatabellaalsuostatonormale(ovverosenzaricerca).

Modifichiamo, quindi, ilmetodo “tableView: numberOfRowsInSection:”, che deveadattarsi a quanto appena detto:

Codice 5.11: Modifica del metodo che imposta il numero di elementi della tabella

Codice 5.12: Modifica del metodo che definisce il contenuto delle celle

1

23

12

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [listaFiltrata count];}

// Configure the cell.cell.textLabel.text = [listaFiltrata objectAtIndex:indexPath.row];

Latabella,quindi,conterràunnumerodielementiparialladimensionedellalistafiltrata.Modifichiamoanchel’istruzionenelmetodo“tableView:cellForRowAtIndexPath:”:

Page 67: Manuale IOS

67

E,diconseguenza,ancheilmetodo“tableView:didSelectRowAtIndexPath:”

Codice 5.14: Cancellazione degli elementi in “lista”

Codice 5.13: Modifica del metodo che gestisce la selezione di una cella

123456789

12

// eliminiamo l’elemento dalla lista originale- (void)rimuoviElemento:(NSString*)item{ for (int i=0; i<[lista count]; i++) { NSString *elemento = [lista objectAtIndex:i]; if ([elemento compare:item] == NSOrderedSame) { [lista removeObjectAtIndex:i]; } }}

// passiamo l’oggetto selezionatoself.detailViewController.detailItem = [listaFiltrata objectAtIndex:indexPath.row];

Codice 5.15: Modifica del metodo che risponde alle cancellazioni

123

45678

9

if (editingStyle == UITableViewCellEditingStyleDelete) { // rimuovo dalla lista originale [self rimuoviElemento:[listaFiltrata objectAtIndex:indexPath.row]]; // eliminiamo l’elemento dalla lista [listaFiltrata removeObjectAtIndex:indexPath.row]; // eliminiamo la cella dalla tabella [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];}

Dobbiamoandareancheamodificareilmetodo“tableView:commitEditingStyle:forRowAtIndexPath:”.Questohabisognodialcuneaccortezzeinpiù,inquantopuòprodurregrossiproblemisenonvieneimplementatoconattenzione.Comeabbiamovisto,talemetodorispondeallecancellazionichel’utenteesegue.Inquestocaso,l’utenteandràadeliminaredeglielementidi“listaFiltrata”:ciòpuòavveniresiaquan-dovieneeseguitaunaricerca,siaquandolatabellaèvisualizzatainmanieranorma-le.Avremobisogno,quindi,diunmetodosupplementare,chesioccupidipropagarelacancellazioneancheall’oggetto“lista”.Ilmetododainserireèilseguente:

Semplicementequestometodoricevecomeparametrol’elementochedeveesserecancellato e scorre l’intra lista per eliminare ogni sua occorrenza.Nonpossiamoragionaresugliindici(comeeravamoabituati)inquandolacancellazionepotrebbeancheavveniredaunaricerca,equindil’indicecheciverrebbepassatononcorri-sponderebbealrealeelementopresentein“lista”.Inserite,ovviamente,anchel’intestazionedelmetodonelfile“MasterViewController.h”.Orapossiamofinalmentemodificareilmetodo“tableView:commitEditingStyle:for-RowAtIndexPath:”(riportosololeistruzionichesubisconodellemodifiche):

c a P I t o l o 5Ta b l e V i e w Tu t o r i a l

Page 68: Manuale IOS

68

Codice 5.16: Implementazione dell’algoritmo di ricerca

1

23456

78910

111213141516

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{ // rimuoviamo tutti gli elementi dalla lista filtrata [listaFiltrata removeAllObjects]; // controlliamo tutti gli elementi della lista se corrispondono alla stringa di ricerca NSString *elemento; for (elemento in lista){ // eseguiamo il confronto NSComparisonResult result = [elemento compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])]; // controlliamo se l’elemento corrisponde alla ricerca if (result == NSOrderedSame){ [listaFiltrata addObject:elemento]; } }}

Comevedeteprimadieliminarel’oggettoda“listaFiltrata”richiamiamoilmetodocheloeliminadall’oggetto“lista”(riga3).Fattociòl’elementovieneeliminatodallalistafiltrataepuòesserepoiaggiornataanchelatabella.Questemodifichesononecessarie,accertatevidieseguirletutteinmanieracorretta.

Implementiamo la ricercaÈarrivatoilmomentodiimplementarelaricercaveraepropria.Iniziamoinserendoall’internodi“MasterViewController.m”l’algoritmodiricercaveroeproprio:

Icommentipresentinelcodicepossonogiàdarviun’indicazionesucometaleme-todofunzioni,mavediamoloneldettaglio.Perprimacosavengonoeliminatituttiglielementipresentinella listafiltrata (riga4), incuiverranno inseriti inuovielementicorrispondentiallastringadiricerca.Conilcilco“for”(riga8)vengonoesaminatiunoadunoglielementidi“lista”,ecomparaticonlastringadiricerca(cheèl’elemento“searchText”).Sel’elementocorrispondeallastringadiricercaessovieneaggiuntoallalistafiltrata(riga13).Questoalgoritmoprevedechel’elementodevecoincidereconlastringadiricerca(ocomunquel’iniziodell’elementodevecoincidereconlaricerca).Seavetenecessitàdifferenti,dovretemodificarelacomparazionetraidueelementiinbaseallevostreesigenze.

Dobbiamoora inserireunmetodo relativoal searchdisplaycontroller.Essovienerichiamatoadognicarattereinseritodall’utentenellabarradiricerca,ecipermettediaverequell’effettodiricerca“indiretta”,ovveroconirisultatichevengonofiltratimanmanochel’utentedigitailtesto.

Page 69: Manuale IOS

69

Ecco il metodo da inserire:

Codice 5.17: Metodo per eseguire la ricerca ad ogni carattere inserito

1

2

345

- (BOOL)searchDisplayController:(UISearchDisplayController *)control-ler shouldReloadTableForSearchString:(NSString *)searchString{ [self filterContentForSearchText:searchString scope: [[self.sear-chDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]]; // Return YES to cause the search result table view to be reloaded return YES;}

Questometodononfaaltrocherichiamare,ognivoltachevieneinseritouncarattere,l’algoritmodiricercacheabbiamoscrittoinprecedenza.

Mancaunultimometodo, cheviene invece invocatoquandosi annulla la ricerca(cliccandosulbottone“Cancel”osulla“x”nelboxdiricerca):

Codice 5.18: Annullare la ricerca

12345

- (void)searchBarCancelButtonClicked:(UISearchBar *)saearchBar { [listaFiltrata removeAllObjects]; [listaFiltrata addObjectsFromArray:lista]; [self.tableView reloadData];}

Quando un utente annulla una ricerca semplicemente ripristiniamo la tabella con gli elementidilista,chedevonoessereriassegnatiancheallalistafiltrata.

Abbiamoconcluso!Cliccatesu“Run”etestatelavostranuovaapplicazione!

c a P I t o l o 5Ta b l e V i e w Tu t o r i a l

Page 70: Manuale IOS

70

Fig. 5.6b: App 5 “TableViewTutorial”Fig. 5.6a: App 5 “TableViewTutorial”

Page 71: Manuale IOS

71

c a P I t o l o 6A c c e s s C o n t a c t

6. AccessContact: utilizziamo i contatti

In questo capitolo andremo ad implementare una funzione un po’ particolare, inquantoaccederemoall’applicazionenativa“Contatti”ericaveremole informazionidi un contatto.

Impareremoadutilizzareilframework“AddressBook”,chemetteadisposizioneleclassielefunzioninecessarieperinteragireconlarubricadiiOS.

Creiamo la struttura graficaCreiamounnuovoprogettodi tipo “SingleViewApplication”echiamiamolo “Ac-cessContact”.Comesempreassicuriamoci che “Use storyboard”e “IncludeUnitTest”sianodisattivati.

Iniziamo creando la struttura dell’unica vista che compone la nostra applicazione.Apriamoquindiilfile“ViewController.xib”edefiniamounastrutturacomelaseguente:

Fig. 6.1: Struttura applicazioni

Sonotutticomponenticheabbiamogiàutilizzato,quindinondovresteaverenessunproblema.C’èunaimageviewperl’immaginedelcontatto,6label(treincuisem-plicementec’èscrittoilnomedelcampo,ealtretrecheospiterannoilvaloreveroeproprio) e un bottone.

Unapiccolaattenzione lamerita la labelchedeveospitareglieventualinumeriditelefono del contatto.

Talelabeldevepotercontenerepiùrighe,quindidovetefareinmodocheoccupipiùspazio(comepoteteosservareinfigura6.2propostanellapaginasuccessiva).

Page 72: Manuale IOS

72

Inoltrenell’“AttributesInspector”impostateilvaloredi“Lines”a4,inmodochetalelabelpossaospitarefinoaquattrolinee:

Fig. 6.2: Dimensione della label Telefono

Fig. 6.3: Attributes Inspector della lable

Dobbiamo ora collegare gli elementi creati alla classe. Collegate le tre label e la ima-geview,creandoirispettivioutlet.Createancheilcollegamentoconilbottone,defi-nendoun’azione“apriContatto”.Lavostraclasse,quindi,dovràesseredefinitacomenel codice proposto nella pagina successiva.

Page 73: Manuale IOS

73

Conclusa la fasedidefinizionedell’interfacciapossiamopassareallascritturadelcodice.

Scriviamo il codice necessarioPrimadiprocedere,dobbiamoimportareilframework“AddressBook”all’internodelnostroprogetto.Per fareciòselezioniamo ilprogettoespostiamocinellasezione“Build Phases”:

Codice 6.1: File di interfaccia ViewController.h

123456789101112

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIImageView *immagine;@property (strong, nonatomic) IBOutlet UILabel *labelNome;@property (strong, nonatomic) IBOutlet UILabel *labelCognome;@property (strong, nonatomic) IBOutlet UILabel *labelTelefono;

- (IBAction)apriContatto:(id)sender;

@end

Fig. 6.4: Sezione “Build Phases” del progetto

Espandiamopoiilgruppo“Link Binary With Libraries”.Quivedremoiframeworkchesonogiàassociatialnostroprogetto(nelnostrocasocisonosolamentequelliessen-zialichetutteleapplicazionidevonoavereperfunzionarecorrettamente).

c a P I t o l o 6A c c e s s C o n t a c t

Page 74: Manuale IOS

74

Clicchiamosulbottone“+”,siapriràunelencodituttiiframeworkdisponibili:

Fig. 6.5: Framework disponibili

Fig. 6.6: Framework aggiunti

Selezioniamo“AddressBook.framework”e“AddressBookUI.framework”eclicchia-mosu“Add”.Abbiamocosìaggiuntoquestidueframeworkalnostroprogetto:orapotremoutilizzarelefunzionicheessicimettonoadisposizione.

Possiamoorainiziareadefinireilcomportamentodellanostraapplicazione.Perprimacosadobbiamofarealcunemodificheall’intestazionedellaclasse“ViewController”:

Codice 6.2: Inserimento del delegato e delle classi necessarie

12345

#import <UIKit/UIKit.h>#import <AddressBook/AddressBook.h>#import <AddressBookUI/AddressBookUI.h>

@interface ViewController : UIViewController <ABPeoplePickerNaviga-tionControllerDelegate>

Page 75: Manuale IOS

75

Abbiamoimportatoledueclassi(contenuteneiframeworkcheabbiamoinseritopocofa)checisarannonecessarieperutilizzareicomponentinecessari(righe2e3),inoltreabbiamo inserito anche il delegato “ABPeoplePickerNavigationControllerDelegate”.Essosarànecessarioperlarealizzazionedell’applicazionechevedremofrapoco.

Spostiamocinelfile“ViewController.m”einiziamoascrivereilcodice.Iniziamodalmetodo“apriContatto”,chetroveretegiàdefinito:

Codice 6.3: Implementazione dell’azione “apriContatto:”

123

45678

- (IBAction)apriContatto:(id)sender { //Crea il picker ABPeoplePickerNavigationController *picker = [[ABPeoplePicker-NavigationController alloc] init]; //Imposta il delegate del picker come vista principale picker.peoplePickerDelegate = self; //Visualizza il picker [self presentModalViewController:picker animated:YES];}

Analizziamoconcalmailcodiceappenaproposto.Perprimacosaabbiamodefinitouncomponente“ABPeoplePickerNavigationController” (riga3):questoè l’oggettochepermettediinteragireconicontattipresentineldispositivo.Verrà,infatti,apertaunanuovavista,lastessachevieneutilizzatenell’applicazione“Contatti”.Ingergoquestocomponentevienespessochiamato“picker”.Nell’istruzionesuccessiva(riga5)impostiamochesialaclassecorrentearisponderealdelegato.Vedremofrapocoqualisonoimetodidadefinireperimplementarecorrettamentetaledelegato.L’ultima istruzione (riga7)è lastessacheabbiamoutilizzatonellocapitolo4,e faapparire la vista del picker.

Dobbiamooradefinirealcunimetodi,necessariinquantolanostraclassesièpresailcompitodirisponderealdelegatodelpicker.Imetodicheimplementeremovengonorichiamatiquandol’utenteeseguedeterminateazioni,vedremoquali.

Iniziamoinserendoilseguentemetodo“peoplePickerNavigationController: shouldCon-tinueAfterSelectingPerson:”(codiceriportatonellapaginasuccessiva).

c a P I t o l o 6A c c e s s C o n t a c t

Page 76: Manuale IOS

76

Questometodovienerichiamatoquandol’utenteselezionaunprecisocontatto.Sioccupa,comepotretenotare,dileggereidatidelcontattoedivisualizzarlinellelabelapposite.Analizziamoalcunedelleistruzioniprincipali.Allariga4leggiamoilnomedelcontatto,sfruttandolaproprietà“kABPersonFirstNa-meProperty”.Essavieneconvertitainstringaeassegnatapoiallalabel.Lostessoprocedimentoèfattoperilcognome.Ovviamentepotetericavareanchealtreinfor-mazionidelcontatto,adesempioilsoprannome,iltitolo,etc.Potetetrovarel’elencocompletodelleproprietàmesseadisposizionedallaclassenelladocumentazioneufficiale.Allariga8ricaviamoinumeriditelefonodelcontatto(lostessoprocedimen-toavremmopotutofarlocongliindirizzimail).Essivengonolettieinseritiinunarray(riga9),inquantopossonoesserediversinumeri.Prima di impostare la label dobbiamo eseguire un controllo: se nessun numero è pre-sente(equindil’arrayhadimensionepariazero)nonpossiamosettarenessunvalorenellalabel,quindicilimitiamoadinseriredeisemplicitrattini(riga13).

Codice 6.4: Metodo per rispondere alla selezione di un contatto

12

34

56

78

9

101112131415161718

192021222324252627282930

- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigation-Controller *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person { // ricaviamo e impostiamo il nome labelNome.text = (__bridge NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty); // ricaviamo e impostiamo il nome labelCognome.text = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty); // ricaviamo i numeri di telefono ABMultiValueRef multi = ABRecordCopyValue(person, kABPer-sonPhoneProperty); NSArray *numeri = (__bridge NSArray*)ABMultiValueCopyArrayOfAllValues(multi); if ([numeri count] == 0) { // nessun numero presente per il contatto labelTelefono.text = @”---”; } else { labelTelefono.text = @””; // stampiamo tutti i numeri di telefono for (int i=0; i < [numeri count]; i++) { labelTelefono.text = [NSString stringWithFor-mat:@”%@ \n%@”,labelTelefono.text,[numeri objectAtIndex:i]]; } } // ricaviamo e visualizziamo l’immagine del contatto NSData *imageData = (__bridge NSData*)ABPersonCopyImageData(person); immagine.image = [UIImage imageWithData:imageData]; //Rimuove il controller “Contatti” [self dismissModalViewControllerAnimated:YES]; return NO;}

Page 77: Manuale IOS

77

Sesonopresentideinumeri,invece,lileggiamotramiteunciclofor(riga17)eliinse-riamo tutti nella label apposita.Infine,l’ultimocampocheandiamoaleggereèl’immaginedelcontatto:essavienelettacomeNSData,cheèunparticolareoggettoper larappresentazionedeidati.VienepoiconvertitainUIImageeassegnataallaimageview(riga24).Inquestocasonondobbiamoeseguirenessuncontrollo,perchèsenonèpresentenessunaimma-gineavremounvalore“null”allavariabilechenoncreaproblemiall’applicazione.L’istruzioneallariga27,infine,rimuoveilpickerdallavista,maanchequestaèun’i-struzionegiàvista.

Abbiamopraticamente scritto laparte fondamentaledellanostraapplicazione!Cirestano solo due veloci metodi da inserire:

Codice 6.5: Altri metodi del delegato del picker

1

2345

678

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{ return NO;}

- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { // facciamo tornare il controller alla vista principale [self dismissModalViewControllerAnimated:YES];}

Ilprimoèuncomportamentochevogliamodefinire:vogliamochequandol’utenteselezionauncontattononvenganoapertiidettaglidelcontattostesso,mailcon-trolloritorniallanostraapplicazione.Se,invece,voletepermettereall’utentedisele-zionaresolounparticolarecampodelcontattodoveteinserire“YES”comevalorediritorno per questo metodo.

Ilsecondometodo,invece,vienerichiamatoquandol’utenteescedalpickersenzaeffettuarenessunascelta,ovveropremendoiltasto“Cancel”.Ovviamentenondo-vremoeseguirenessunaapplicazione,masemplicementerimuovereilpicker.

Abbiamoconcluso!Cliccatesu“Run”etestatelavostranuovaapplicazione!

c a P I t o l o 6A c c e s s C o n t a c t

Page 78: Manuale IOS

78

Fig. 6.7: App 6 “AccessContact”

Page 79: Manuale IOS

79

c a P I t o l o 7X M L Tu t o r i a l

7. XML

Dopo aver visto la maggior parte dei componenti principali, vedremo nei prossi-miduecapitolicomeinteragireconidatidavisualizzarenellanostraapplicazione.Inizieremodaunatecnologiamoltoutilizzata,specialmenteinambitoweb:stiamoparlando di XML.

Vedremo,quindi,comeleggereunfileXML,dacuiricavaredelle informazionicheabbiamosalvato.Questaoperazioneverràeseguitainlocale(ovveroilfilexmlsaràall’internodelnostroprogetto),manullavietadiavereilfilecaricatosuunserverwebdacuiaccederetramitelanostraapplicazione.

Cosa è XMLXMLèunmetalinguaggiodimarkup(attenzione,nonèpropriamenteunlinguaggiodiprogrammazione),ovverounlinguaggiocheconsentediestendereocontrollareilcomportamento di altri linguaggi. Il linguaggio di markup più famoso è sicuramente l’HTML,chehamolteanalogieconXML.

XML è l’acronimo di eXtensible Markup Language, da cui possiamo capire la carat-teristicafondamentalediquestolinguaggio:cipermettedicrearetagpersonalizzati,inbaseallenostreesigenze.

Saràpiùsemplicecomprenderecomefunzionaquestolinguaggiomedianteunesempio:

XML 1: Esempio

<?xml version=”1.0” encoding=”ISO-8859-1”?><studenti> <studente> <matricola>000001</matricola> <cognome>Rossi</cognome> <nome>Paolo</nome> </studente> <studente> <matricola>000002</matricola> <cognome>Verdi</cognome> <nome>Francesco</nome> </studente></studenti>

LaprimarigadefiniscelaversionediXMLinusoelacodificautilizzata(secondolenormeISO).Dallasecondarigainpoi,invece,troviamodeitagpersonalizzati,chevanno a modellare dei dati a nostro piacimento.

Possiamovederecomeabbiamodefinitountaggenerale“studenti”,chevieneiniziatoallasecondarigaeconclusoall’ultima.Nelmezzotroviamo,invece,altritag,cheripor-tanoleinformazionichevogliamomemorizzare,perpoiutilizzarleanostropiacimento.

Page 80: Manuale IOS

80

Ci sono alcune piccole regole da rispettare nella struttura XML:

1)Itagnonpossonoiniziareconnumeriocaratterispecialienonpossonocontenerespazi:

•corretti:<nome>,<cognome>,<dataDiNascita>•errati:<&soldi>,<12peso>,<annodinascita>

2)Itagdevonoesserebilanciati(ognitagapertodeveesserechiuso):•corretto:<nome>Andrea</nome>•errato:<nome>Andrea

3) I tag non devono contenere errori di annidamento.Ecco alcuni esempi errati:

XML 2: Esempi errati

XML 3: Esempio

<rubrica> <nome>Mario</nome> <cognome>Rossi</rubrica>

<rubrica> <nome>Mario</nome> <cognome>Rossi</rubrica></cognome>

<rubrica> <nome>Mario</nome> <cognome>Rossi</COGNOME></rubrica>

<studenti> <studente> <matricola value=”000001” /> <cognome value=”Rossi” /> <nome value=”Paolo” /> </studente> <studente> <matricola value=”000002” /> <cognome value=”Verdi” /> <nome value=”Francesco” /> </studente></studenti>

4)Sipossonoinseriredegliattributiall’internodeitag;lastrutturasaràquindilase-guente:<nometagattributo1=“valore1”attributo2=“valore2”>Valore</nometag>Inostrielementi,quindi,potrannoesserescrittianchenellaseguentemaniera:

Page 81: Manuale IOS

81

Questastrutturaèdeltuttougualeaquellaprecedente.Notatecheinquestocasonon abbiamo usato il tag di chiusura,ma abbiamo inserito “/” all’interno del tagstessoproprioper indicarechequel tagnonhaelementodichiusura.Quellochecambierà sarà solamente il modo di leggere i valori via codice.

XML nella programmazione per iOSPer ora abbiamo fatto una panoramica generale su XML, presentando gli aspetti fondamentali di tale linguaggio. Ma come possiamo integrarlo con le nostre applica-zioni?L’oggettochesioccupadirecuperareidatidaunfileXMLvienedettoparser.

Esistonovaritipidiparser(diversiperlinguaggietecnologie),quellochenoiandre-moadutilizzare rientranellacategoriadeiSAX.Lacaratteristica fondamentalediquestoparserstanelfattocheprocessaidocumentilineaperlinea:datiacuisièaccedutoinprecedenzanonpossonoessererilettisenzalarielaborazionedell’interodocumento.Puòessereunosvantaggio,mailparserdisponibilenelSDKlavorainquesto modo.

Andremooraarealizzareun’applicazionemoltosemplice,chevisualizzeràsulloscher-moidatilettidalunfileXMLpresentenell’applicazionestessa.Nulladicomplesso,quindi,maèunbuonmodoperprendereunpo’diconfidenzaconXML.

Creiamo la struttura graficaCreiamounnuovoprogettoditipo“SingleViewApplication”echiamiamolo“XML-Tutorial”.Comesempreassicuriamociche“Usestoryboard”e“IncludeUnitTest”siano disattivati.

Iniziamocreandolastrutturadell’unicavistachecomponelanostraapplicazione.Apriamoquindiilfile“ViewController.xib”edefiniamounastrutturacomelaseguente:

Fig. 7.1: Struttura di “XMLTutorial”

c a P I t o l o 7X M L Tu t o r i a l

Page 82: Manuale IOS

82

Semplicementec’èunbottoneeunatextview,componentechenonabbiamomaivisto.Essapermettedivisualizzaregrandiporzioniditesto,graziealloscrollgiàpresentenelcomponente.Permette, inoltre,dimodificare il testocontenutoalsuo interno,comeunasortadieditor.Questa,però,nonèunafunzionalitàchevogliamonellano-straapplicazione,quindiselezioniamotalecomponenteenell’”AttributesInspector”togliamolaspuntaallaproprietà“Editable”:

Fig. 7.2: Deselezione di “Editable”

Creiamo,ora,icollegamenticonlaclasse“ViewController”.Definiamounoutletperlatextviewechiamiamola“viewTesto”,eun’azioneassociataalbottoneconilnome“avviaParsing”.Laclasse“ViewController.h”saràquindicosìdefinita:

Codice 7.1: File di interfaccia ViewController.h

123456789

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (strong, nonatomic) IBOutlet UITextView *viewTesto;

- (IBAction)avviaParsing:(id)sender;

@end

Page 83: Manuale IOS

83

Scriviamo il codice necessarioPrima di procedere con il codice necessario, dobbiamo inserire all’interno del pro-gettoilfilexmlconinostridati.Trascinateilfilexml(chepotetecreareex-novo,op-pure creare copiando il codice presentato nella prima parte di questo tutorial tutorial) all’internodelnostroprogetto,spuntandocomesemprel’opzione“Copy items into destination group’s folder (if needed)”.

Iniziamoinserendoundelegatonelladefinizionedellaclasse“ViewController.h”:

Codice 7.2: Delegato per il parser del file XML

Codice 7.3: DImplementazione dell’azione “avviaParsing:”

123456789

12345

6789

101112

131415

161718

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <NSXMLParserDelegate>

@property (strong, nonatomic) IBOutlet UITextView *viewTesto;

- (IBAction)avviaParsing:(id)sender;

@end

- (IBAction)avviaParsing:(id)sender { // azzeriamo il contenuto della text view [viewTesto setText:@””]; // definiamo il percorso del db NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@”dati.xml”]; // convertiamo il path del file in un NSURL NSURL *xmlURL = [NSURL fileURLWithPath:path]; // creiamo il parser NSXMLParser *parser = [[ NSXMLParser alloc] initWithContentsOfURL:xmlURL]; // settiamo come delegato la classe stessa parser.delegate = self; // effettuiamo il parsing del file e controlliamo se ci sono stati problemi if([parser parse] == NO){ // errori nel parsing UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”Attenzione” message:@”Ci sono stati dei problemi nel par-sing del file” delegate:nil cancelButtonTitle:@”OK” otherButtonTitles: nil]; [alert show]; } }

Abbiamoinseritoladichiarazionedeldelegato“NSXMLParserDelegate”(riga3),checiforniràdeimetodiutiliperilparserdelfileXML.

Spostiamocinelfile“ViewController.m”edefiniamol’azione“avviaParsing:”

c a P I t o l o 7X M L Tu t o r i a l

Page 84: Manuale IOS

84

Perprimacosavienedefinitoilpercorsodelfile(riga3),chesitrovanellacartelladell’applicazionestessa.Taleistruzionepotrebbesembrarecomplessa,maessanonfaaltrocherilevareilpercorsoincuisitroval’applicazione(siaessasuiPhoneSi-mulatorchesuiPhonefisico)eaggiungereatalepercorso“dati.xml”,cheèproprioilpercorsocompletodelnostrofileXML.SuccessivamentequestopercorsovieneconvertitoinunoggettoNSURL(riga5),inquandoènecessarioperchiamarepoiilmetodocheesegueilparsing.Allariga7inizializziamol’oggettochesideveoccuparedieseguireilparsing,acuivienesettatopoicomedelegatolaclassecorrente(riga9).Ciòsignificachesaràpropriolaclasse“ViewController”agestireimetodiinvocatidaldelegatoNSXMLParserDelegate.Allariga11,infine,vieneavviatoilparsingdelfile,dicuipoivienecontrollatol’esito:seessohaavutoesitonegativo,equindic’èstato un qualsiasi errore, viene mostrato all’utente un messaggi di errore.

Oradobbiamodefinireimetodichesioccupanodileggereilfilexml.Essisonometodideldelegatocheabbiamodefinito,quindidevonoesseretuttipre-sentinellanostraapplicazione.

Iniziamoinserendotalemetodo:

Codice 7.4: Definizione dell’azione “avviaParsing”

1

234

567

8910

111213

141516

1718

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)ele-mentName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict { if ([elementName isEqualToString:@”studenti”]){ [viewTesto setText:[[NSString alloc] initWithFormat:@”%@\nInizio studenti”,viewTesto.text]]; } else if([elementName isEqualToString:@”studente”]){ [viewTesto setText:[[NSString alloc] initWithFormat:@”%@\nNuovo studente”,viewTesto.text]]; } else if([elementName isEqualToString:@”matricola”]) { [viewTesto setText:[[NSString alloc] initWithFormat:@”%@\nMatricola: “,viewTesto.text]]; } else if([elementName isEqualToString:@”cognome”]) { [viewTesto setText:[[NSString alloc] initWithFormat:@”%@\nCognome: “,viewTesto.text]]; } else if([elementName isEqualToString:@”nome”]) { [viewTesto setText:[[NSString alloc] initWithFormat:@”%@\nNome: “,viewTesto.text]]; }}

Comepoteteosservare,visonounaseriedicontrolliif,chevannoacontrollarel’ele-mentocorrentecheèstatoindividuatodalparser.Inbaseall’elementovieneinseritaunastringaadeguatanellatextviewcheabbiamopredisposto.

Page 85: Manuale IOS

85

Questoprocessoèpossibileperchéconosciamoapriorilastrutturadelfilexml:que-stoèquasisemprevero,inquantosarebbemoltopiùcomplicatoleggereunfilexmldi cui non conosciamo la struttura interna. Ilmetodovieneovviamente richiamatoognivoltache ilparser incontraunnuovoelemento, cioè l’apertura di un tag.

Percompletarel’applicazionemancanosoloduemetodi:

Codice 7.5: Altri metodi del delegato NSXMLParser

1

2

345

6

7

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { [viewTesto setText:[[NSString alloc] initWithFormat:@”%@%@”,viewTesto.text,string]];}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)ele-mentName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { [viewTesto setText:[[NSString alloc] initWithFormat:@”%@\nFine elemento: %@”,viewTesto.text,elementName]];}

Ilprimometodovienerichiamatoquandoilparserincontraunvaloreracchiusotraduetag(l’informazioneveraepropria).Nelnostrocasocilimitiamoainserirlanellatextview,peròpotrestefaredelleoperazionipiùomenocomplessesulleinformazioni cheleggetedalfile.

Ilsecondoeultimometodo,invece,vienerichiamatoquandoilparserincontrauntagdichiusura.Ancheinquestocasol’unicaazionechefaremosaràquellodiinserireuna stringa nella text view.

Abbiamoterminato!Cliccatesu“Run”etestateilvostroparserdidocumentixml!

c a P I t o l o 7X M L Tu t o r i a l

Page 86: Manuale IOS

86

Fig. 7.3: App 7 “XMLTutorial”

Page 87: Manuale IOS

87

c a P I t o l o 8S Q L Tu t o r i a l

8. SQL

NelcapitoloprecedenteabbiamovistocomeleggereunfileXMLefareilparsingdeidaticontenutialsuointerno.Nonè,però,l’unicapossibilitàperaccedereadunar-chiviodidati.LatecnologiamaggiormenteutilizzataèsicuramenteSQL,chesibasasudatabaserelazionali.InquestocapitolovedremocomesfruttareSQLiteperutiliz-zareundatabasedisponibileinlocale(quindisalvatoall’internodelnostroprogetto). Creeremo, quindi, una tabella in cui andremo ad inserire i valori letti dal nostro data-base,dopoavereseguitounaquerypredefinita.Vedremo,inoltre,comeeseguireleazionipiùcomuni:inserimentoecancellazionediunelemento.

DevopremetterechenonparleròdiSQLedatabaserelazionali,chedevonoesseregiàconosciutidachiaffrontaquestocapitolo.Èunasceltachepotrebbenonpiacereamoltidivoi,peròrichiederebbetroppotempoeunatrattazionechenonpuòesserefattainunsemplicetutorial.Dettociò,èpossibileseguirequestaguidaeconcludereconsuccessol’applicazione,anchesenzaconoscerenientediSQL,ovviamenteal-cunecaratteristicheealcunipassaggipotrebberorisultaredidifficilecomprensione.

In questa guida sentirete spesso parlare di SQLite, ma cosa è di preciso?SQLiteèunalibreriacheimplementaunDBMSSQL,permettendodicreareunda-tabaseall’internodiununicofile.Essoèmoltoindicatoperscopicomeilnostro,ov-verolacreazionediapplicazioniperdispositivimobili,chenonpossonopermettersidi avere un DMBS dedicato per la gestione delle basi di dati. Ovviamente fornisce un supportoparzialeadSQL,inquantomancadialcunecaratteristicheavanzate,cheperòdubitopossiateutilizzareall’internodiun’applicazione.SQLite,comunque,èmoltoveloceeleggero,perfettoquindiperapplicazionimobile.

Nota: molti utenti in passato mi hanno chiesto come utilizzare un database MySQL (risiedente su un server) all’interno delle applicazioni. Purtroppo non è disponibile nessun componente che permetta di fare ciò, quindi dovrete utilizzare un web service che faccia da collegamento tra la vostra applicazione e il database stesso.

Page 88: Manuale IOS

88

Creiamo il databaseLaprimacosadafareècreareildatabasecheutilizzeremopoinellanostraappli-cazione.Per fareciòutilizzeremo“Navicat forSQLite”,unprogrammachepotetetrovare sul sito navicat.com.

Fig. 8.1: “Navicat for SQLite”

Fig. 8.2: New Connection

Apriteilprogrammaecliccatesu“Connection”.Siapriràunaschermataincuidovre-te inserire il nome del vostro database e il percorso in cui salvarlo:

Page 89: Manuale IOS

89

Inseriteunnome(nelmiocasohoutilizzato“squadre”),selezionate“NewSQLite3”esceglieteunpercorsoincuisalvareilfile.Abbiamocosìcreatoilnostrodatabase,cheperòdobbiamoancoradefinire.Vogliamocreareunasemplicestruttura,incuipossiamoinserireilnomedialcunesquadreelarelativanazionalità.Fatedoppioclicsulnomedellavostraconnessioneesuccessivamentesu“main”.Quiavremodiverseazionidapotereffettuare,comevisualizzarelastrutturadeldboppureeseguiredelleinterrogazioni.Selezionate“Tables”efateclicsulbottone“+”chetrovatenellabarrainbasso:

Fig. 8.3: Sezione Tables di “Navicat for SQLite Lite”

Così facendo avremo la possibilità di definire una nuova tabella. Iniziamo inse-rendouncampodinome “id”, chesarà l’identificativounivocodiogni elemento. Selezionate“integer”cometipo,spuntatelacolonna“Key”el’opzione“Autoincre-ment”(Vedifig.8.4).

c a P I t o l o 8S Q L Tu t o r i a l

Page 90: Manuale IOS

90

Inquestomodoavremouncamponumericochesiincrementeràautomaticamenteadogninuovoelementoinserito,eserviràcomeidentificativounivocodiognielemento.Perinserireunnuovocampocliccatesulbottone“AddField”chetrovatenellabarrasuperiore.Inserite,quindi,duenuovicampitestuali:“squadra”e“nazione”.Quando avrete terminato dovreste vedere il seguente risultato:

Fig. 8.4: Definizione del campo “id” della tabella

Fig. 8.5: Definizione dei campi “squadra” e “nazione”

Page 91: Manuale IOS

91

Noncirestachecliccaresulbottone“Save”einserire“squadre”comenomedellanostratabella.Abbiamocosìcreatoilnostrodatabase!Oranellaschermata“Tables”dovrestevederelatabellaappenadefinita(eun’altratabellacheilprogrammacreainautomatico):

Fig. 8.6: Tabella “squadre definita correttamente

Noncirestacheinserirealcunivaloriall’internodelnostrodatabase,inmododanonavereun’applicazionevuota.Spostiamociin“Queries”eclicchiamoancorasul“+”nellabarra inferiore.Questavoltasiapriràunaschermatachepermetterà l’inseri-mento di qualsiasi genere di query.

Fig. 8.7: Inserimento di alcuni valori

c a P I t o l o 8S Q L Tu t o r i a l

Page 92: Manuale IOS

92

Inseriamo le seguenti query:

Fig. 8.8: Esecuzione delle query

SQL 1: Query

INSERT INTO squadre (squadra, nazione) VALUES (‘Juventus’,’Italia’);INSERT INTO squadre (squadra, nazione) VALUES (‘Milan’,’Italia’);INSERT INTO squadre (squadra, nazione) VALUES (‘Chelsea’,’Inghilterra’);INSERT INTO squadre (squadra, nazione) VALUES (‘Real Madrid’,’Spagna’);INSERT INTO squadre (squadra, nazione) VALUES (‘Lione’,’Francia’);INSERT INTO squadre (squadra, nazione) VALUES (‘Porto’,’Portogallo’);

Epremiamopoisu“Run”pereseguirle.Seaveteeseguitotuttocorrettamentenonviverranno restituiti messaggi di errore:

Tornateallaschermatainizialeeselezionatelavostratabella.Conundoppioclicviverràapertaunaschermataincuivisualizzereteglielementipresentineldb,ovveroproprioquellicheabbiamoappenainserito(Vedifig.8.9).

Page 93: Manuale IOS

93

Ilnostrodatabaseècosìprontoperessereutilizzatoall’internodell’applicazione!

Fig. 8.9: Database popolato

c a P I t o l o 8S Q L Tu t o r i a l

Page 94: Manuale IOS

94

Creiamo la struttura dell’applicazioneCreiamounnuovoprogettoditipo“MasterDetailApplication”echiamiamolo“sql-Tutorial”.Comesempreassicuriamociche“Usestoryboard”e“IncludeUnitTest”siano disattivati. Come abbiamo visto nel capitolo 5, questo template ci fornisce un’implementazionedibaseperunatabella,incuinoiandremoadinserireivaloriletti dal database.

Dobbiamo,però,inserirealtreduecosemoltoimportanti:unaclassechesioccuperàdicomunicareconildatabase,elalibreriachepermettetalecomunicazione.Iniziamocreandolaclassecheserviràainostriscopi.Andiamoin“File->New->NewFile…”ecreiamouna“Objective-Cclass”,chiamandolasemplicemente“Data”:

Fig. 8.10: Creiamo una nuova classe

DobbiamoorainserireilframeworkcheforniscelefunzioniperutilizzareSQLite:ilpro-cedimento è lo stesso che abbiamo visto negli scorsi capitoli. Spostiamoci, quindi,in “BuildPhases”epoi in “LinkBinaryWithLibraries”eaggiungiamo il framework“libsqlite3.0.dylib”(comepotetevedereinfig8.11e8.12).

Page 95: Manuale IOS

95

Infine,prendiamoilfile“squadre.sqlite”e trasciniamolo all’interno del nostro progetto, spuntando l’opzione “Copyitemsintodestinationgroup’sfolder(ifneeded)”comealsolito.

Abbiamocosìcompletatoladefinizionedellastrutturadellanostraapplicazione.

Se avete eseguito tutto in maniera cor-retta dovreste avere un progetto come quellopropostoinfigura8.13.

Fig. 8.11: Aggiunta della libreria libsqlite3.0.dylib

Fig. 8.13: Struttura del progetto

Fig. 8.12: Libreria aggiunta correttamente

c a P I t o l o 8S Q L Tu t o r i a l

Page 96: Manuale IOS

96

Definiamo la classe “Data”Dobbiamooraimplementarelaclasse“Data”,sucuisibasagranpartedique-stocapitolo.Primadiiniziareascriverecodice,focalizziamol’attenzionesuciòchedeve fare questa classe.

Essa avrà il compito di:•creareunaconnessioneconildatabaselocale;•interrogarelabasedidatieseguendounaquerypredefinita,salvandoirisultatiinunarray;

•cancellareunelementodaldatabasesurichiestadell’utente;•inserireunnuovoelementoall’internodeldatabase.

Inizieremoadanalizzareiprimiduepunti,ovveroilcollegamentoaldatabaseel’esecu-zionediunasemplicequery,checirestituiràtuttiglielementipresentinellabasedidati.

Iniziamoaprendoilfile“Data.h”einserendoilseguentecodice:

Codice 8.1: Definizione del file di interfaccia Data.h

12345678910111213141516

#import <Foundation/Foundation.h>#import <sqlite3.h>

@interface Data : NSObject { NSString *pathDB; NSMutableArray *lista;}

@property (nonatomic, retain) NSMutableArray *lista;

- (void)caricaValori;- (void)cancellaSquadra:(NSMutableDictionary*)squadra;- (void)aggiungiSquadra:(NSMutableDictionary*)squadra;

@end

Allariga2abbiamoimportatolaclassenecessariaperutilizzareidatabaseSQLitein Cocoa. Ledefinizionisuccessivesonosemplici:abbiamodefinitounastringa (riga5)checonterràilpercorsodeldatabaseeunalista(riga7),cheinvececonterràtuttigliele-menti letti dal database. Diquestalistaabbiamodefinitoanchelaproperty, inquandopoivorremoleggerel’elementoanchealdifuoridellaclasse.Letreazioni(righe12,13e14),infine,implementarannoicomportamentipossibilisulnostrodatabase(letturavalori,cancellazioneeinserimentodiunnuovoelemento).

Page 97: Manuale IOS

97

Spostiamocinelfile“Data.m”einiziamoadimplementarelaclasse:

Codice 8.2: Implementazione del metodo “init”

12345678910111213

1415161718

#import “Data.h”

static sqlite3 *database = nil;

@implementation Data

@synthesize lista;

- (id)init{ self = [super init]; if (self) { // definiamo il percorso del db pathDB = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@”squadre.sqlite”]; // leggiamo tutti gli elementi [self caricaValori]; } return self;}

Laprimaistruzioneparticolarecompareallariga3,edèladefinizionedell’oggettocheciserviràpercrearelaconnessioneconildatabase.Comeavreteormaiimparato,allariga7c’èla“synthesize”dellaproprietàlistacheabbiamodefinitonellaclassediinterfaccia.Allariga9vienedichiaratoilmetodo“init”,chevieneinvocatoquandosiinizializzaunnuovooggettoditipoData.Talemetodohaunastrutturachepotrebbesembrareunpo’strana:primarichiamailmetodo“init”dellasuperclasse(equindidellaclas-seNSObjectchevieneereditatadaqualsiasioggetto),poivienefattouncontrollosull’oggetto“self”.Sel’oggettoèstatoinizializzatoinmanieracorrettapossonoes-sereeseguitealtredefinizioni,propriocomeabbiamofattonoi.All’internodell’if,infatti,abbiamodefinitoilpercorsodelnostrodatabase(riga13),epoiabbiamorichiamatoilmetodochesioccuperàdicaricareivaloridaldatabase.L’istruzionecheleggeilpercorsodi“pathDB”èlastessacheabbiamovistonelpre-cedente capitolo.

Dobbiamoora implementare ilmetodo“caricaValori”,chedeve legge tuttigliele-menti dal database. Nella pagina successiva troverete il codice da inserire per la sua implementazione.

c a P I t o l o 8S Q L Tu t o r i a l

Page 98: Manuale IOS

98

Analizziamoconcalmaquestometodo,chepotrebbenonesseresemplicepermoltidivoi.PerprimacosavienedefinitounoggettoditipoNSMutableArray(riga4),chesarà una lista temporanea in cui inseriremo uno alla volta gli elementi letti dal databa-se. Questa lista, poi, diventerà proprio la lista degli oggetti della nostra classe.Alla riga 6 viene aperta la connessione con il database: essa si trova all’interno di un costrutto“if”:setalecontrollodaesitopositivo,sipossonoelaborareidati,altrimentisipassaallafinedelmetodo,inquantononèpossibileinstaurarelaconnessione.Se la connessioneè stata creata, possiamocreare laquery cheandremopoi adeseguire (riga8).Alla riga11vieneeseguita talequery:anche inquestocaso,sel’esecuzionehaavutosuccesso,possiamoricavareivaloridesiderati,altrimentinonverràeseguitanessunaoperazione.

Codice 8.3: Implementazione del metodo “caricaValori”

123456

78

91011

12

1314

15

16

17

18

1920212223242526

// Carica i valori dal database passato come parametro- (void)caricaValori { // lista temporanea NSMutableArray *listaTemp = [[NSMutableArray alloc] init]; if (sqlite3_open([pathDB UTF8String], &database) == SQLITE_OK) { // query che ricava i valori const char *sql = “SELECT id, squadra, nazione FROM squadre”; sqlite3_stmt *select_statement; if(sqlite3_prepare_v2(database, sql, -1, &select_state-ment, NULL) == SQLITE_OK) { while(sqlite3_step(select_statement) == SQLITE_ROW) { // ricaviamo i valori letti dalla query NSString *idSquadra = [NSString stringWithUTF8String:(char *)sqlite3_column_text(select_statement, 0)]; NSString *nome = [NSString stringWithUTF8String:(char *)sqlite3_column_text(select_statement, 1)]; NSString *nazione = [NSString stringWithUTF8String:(char *)sqlite3_column_text(select_statement, 2)]; // inseriamo tutti i valori letti in un uni-co oggetto NSDictionary *dictionary = [[NSMutable-Dictionary alloc] initWithObjectsAndKeys:idSquadra, @”id”, nome, @”squadra”, nazione, @”nazione”, nil]; [listaTemp addObject:dictionary]; } } self.lista = listaTemp; sqlite3_finalize(select_statement); } sqlite3_close(database);}

Page 99: Manuale IOS

99

Il ciclo while (riga 12) ci permetterà di scorrere tutti i risultati della nostra query(chepotrebberoessere,ovviamente,piùdiuno), finoal termine.Vengono ricava-ti i varicampi,chevengonomemorizzati invariabili testuali (adesempio riga14). Essi, poi, vengono inseriti in un oggetto di tipo “NSMutableDictionary” (riga 18). Inquestoparticolareoggettoognielementoèassociatoadunachiave,ilcherendemol-to comodo e veloce inserire e recuperare oggetti. Nelnostrocaso,inseriamoitrecampilettiassociandoadognunounachiavediversa:“id”,“squadra”e“nazione”.Successivamentevedremocomerecuperareivalorideside-rati da questo tipo di oggetto.L’elementodizionariovienepoiinseritonellalistatemporanea(riga19).Finitoilciclo,talelistavieneassociataallalistadellaclasse,checonterràquindituttiivalorilettidal database. Fattociòvienechiusalaconnessioneconildb.

Il procedimento potrebbe sembrarvi un po’ complicato, ma in linea generale è sem-prelostessodautilizzare.Ilmioconsiglioèquellodifareunpo’dipraticaperassi-milare bene i concetti.

Perorafermiamociquiconladefinizionedellaclasse“Data”,eandiamoacomple-tarel’applicazione.

Mostriamo i valori del databasePervisualizzareivalorilettidaldatabaseabbiamosceltounatabella,cheabbiamogiàampiamentedescrittonelcapitolo5.Nonmisoffermerò,quindi,sugliaspettigià visti.

Iniziamoaprendoilfile“MasterViewController.h”einseriamolaseguentedefinizione:

Codice 8.4: Definizione del file di interfaccia MasterViewController.h

12345678910111213

#import <UIKit/UIKit.h>#import “Data.h”

@class DetailViewController;

@interface MasterViewController : UITableViewController { Data *dataList;}

@property (strong, nonatomic) DetailViewController *detailViewCon-troller;

@end

SemplicementeabbiamodefinitounoggettoditipoData,cheabbiamochiamato“da-taList”(riga7).Questooggettosarànecessarioperinteragireconildatabaseelegger-neisuoivalori.Ricordatevidiinserireanchel’importazioneditaleclasse(riga2).

c a P I t o l o 8S Q L Tu t o r i a l

Page 100: Manuale IOS

100

Spostiamocioranelfile“MasterViewController.m”einseriamoilseguentecodicenelmetodo“viewDidLoad”:

Codice 8.6: Implementazione dei metodi per definire il contenuto della tabella

Codice 8.5: Implementazione del metodo “viewDidLoad”

12345678

9101112

1314

15

16171819

20212223

123456

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return [dataList.lista count];}

// Customize the appearance of table view cells.- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifier = @”Cell”; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; cell.accessoryType = UITableViewCellAccessoryDisclosu-reIndicator; }

// Configure the cell. NSMutableDictionary *squadra = [dataList.lista objectAtIndex:indexPath.row]; cell.textLabel.text = [squadra objectForKey:@”squadra”]; cell.detailTextLabel.text = [squadra objectForKey:@”nazione”]; return cell;}

- (void)viewDidLoad { [super viewDidLoad]; // inizializziamo l’oggetto Data dataList = [[Data alloc] init];}

Vieneallocatoeinizializzatol’oggetto“dataList”.Lachiamataalsuometodo“init”provocherà l’esecuzionedelleazionicheabbiamovistopocofa: ladefinizionedelpercorsodeldatabaseelaletturadeglielementitramiteilmetodo“caricaValori”.

Dobbiamoimpostare iduemetodichecipermettonodidefinire ilcontenutodellatabella;eccoli:

Page 101: Manuale IOS

101

Dovreste già conoscerli entrambi, se avete dei dubbi vi consiglio di rileggervi il ca-pitolo5.Notatecheentrambiimetodiutilizzanol’oggetto“lista”di“dataList”:infattiusando“dataList.lista”siaccedealla listacon tutti i valori lettidaldatabase,chepossono essere così mostrati nella tabella.L’unicopuntosucuimivogliosoffermareè l’utilizzodeldizionarioalla riga19. Inprecedenzaabbiamovistocomecreareunelementodizionario,qui,invece,vedetecomesiutilizza.Primavienericavatodallalistal’elementodavisualizzare(riga19),poivengonoutilizzatiisuoicampi.Per accedere, ad esempio, al nome della squadra basta utilizzare il metodo“objectForKey:”especificarelachiavedell’elementochesivuoleleggere,inquestocaso“squadra”.Così facendociverràrestituito ilnomedellasquadra, inmanieraveloceesemplice.Lostessoavvieneperlanazionalità,maavremmoanchepotutofarloperl’id,inquandotuttiglielementisonopresentineldizionario.

Abbiamoconclusoquestaparte!Cliccate“Run”econtrollatecheglielementisianovisualizzaticorrettamente.

Fig. 8.14a: App 8 Beta “SQLTutorial”

c a P I t o l o 8S Q L Tu t o r i a l

Page 102: Manuale IOS

102

Cancellazione di un elementoOracheabbiamodefinitoilcomportamentobasilaredellanostraapplicazione,possia-moaggiungereleduefunzionimancanti.Iniziamodallacancellazionediunelemento.L’ideaepartedelfunzionamentoèlastessacheabbiamovistonelcapitolo5,maque-stavoltadobbiamoeliminarel’elementononsolodallalista,maanchedaldatabase.Ciservirà,quindi,unmetodospecificocheeseguataleoperazione.Questometodoè“cancellaSquadra:”,dicuiavevamogiàinseritol’intestazionenellaclasseData.

Andiamoin“Data.m”edimplementiamotalemetodo:

Codice 8.7: Implementazione del metodo “cancellaSquadra:”

123

45

678910

1112131415161718192021

- (void)cancellaSquadra:(NSMutableDictionary*)squadra{ if (sqlite3_open([pathDB UTF8String], &database) == SQLITE_OK) { // query per la cancellazione di una squadra NSString *query = [NSString stringWithFormat:@”DELETE FROM squadre WHERE id=%@”,[squadra objectForKey:@”id”]]; const char *sql = [query UTF8String]; sqlite3_stmt *delete_statement; // eseguiamo la query if(sqlite3_prepare_v2(database, sql, -1, &delete_state-ment, NULL) == SQLITE_OK) { if(sqlite3_step(delete_statement) == SQLITE_DONE) { // tutto ok, ricarichiamo la lista [self caricaValori]; } } // chiudiamo il db sqlite3_finalize(delete_statement); } sqlite3_close(database);}

Potetevederecomepartedelcodicesiamoltosimileaquellopresentein“caricaValori”. Quellochecambiaè,ovviamente,laquerydaeseguire,chedeveessereunadelete(riga5).Inessa,infatti,specifichiamochedeveessereeliminatol’elementoilcuiidcorrispondeaquelloall’oggetto“squadra”.Sel’esecuzionedellaquerydaesitopositivo,dobbiamoricaricareivalorideldb,inmododaaverelalistadeglielementiaggiornata(riga14).Potremmo,inverità,limitarciadeliminarel’oggettodallalista,senzabisognodirica-ricare tutti i valori. Decidete voi quale sistema preferite. Sicuramente ricaricare tutti gli elementi dal database è più dispendioso in termini di risorseeditempo,perògarantiscedinonavereincongruenzetralalistaeivaloripresenti nel database.

Page 103: Manuale IOS

103

Ilmetodoèquindipronto,noncirestacherichiamarloalmomentoopportuno.Perfareciòspostiamocinelfile“MasterViewController.”emodifichiamoilmetodocherispondeall’eliminazionediunelementonellatabella(comegiàvistonelcap.5):

Codice 8.8: Modifica del metodo per l’eliminazione di un elemento

1

23

45

67

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [dataList cancellaSquadra:[dataList.lista objectAtIndex:indexPath.row]]; // Delete the row from the data source. [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; } }

Questometodol’abbiamogiàanalizzato,maquellochequestavoltacambiaèl’i-struzioneallariga3:richiamiamo,infatti,ilmetodo“cancellaSquadra:”cheabbiamoappenadefinito.Atalemetodopassiamol’elementochel’utentehasceltodicancel-lare.Essosaràquindirimossoanchedaldatabase.

Fatto!Testiamolanostraapplicazioneecontrolliamochelacancellazionefunzionicorrettamente.

c a P I t o l o 8S Q L Tu t o r i a l

Page 104: Manuale IOS

104

Fig. 8.14c: App 8 Beta “SQLTutorial”Fig. 8.14b: App 8 Beta “SQLTutorial”

Page 105: Manuale IOS

105

Inserimento di un nuovo elementoInquestaultimapartecidedichiamoadunafunzionalitàmoltoimportanteinappli-cazionicheutilizzanoundatabase:l’aggiuntadinuovielementi.Permetteremoall’u-tentediinserireunanuovasquadra,conlarelativanazionalità,cheverràpoiinseritaall’interno del database. Per fare ciò creeremo una vista apposita, in cui l’utentepotràinserireleinformazioninecessarie.

Iniziamodefinendo ilmetodochedovrà inserireall’internodeldatabase lanuovasquadra. Anche per esso avevamogià definito l’intestazione “aggiungiSquadra:”,eccol’implementazionedainserirein“Data.m”:

Codice 8.7: Implementazione del metodo “aggiungiSquadra:”

123

45

678910

1112131415161718192021

- (void)aggiungiSquadra:(NSMutableDictionary*)squadra{ if (sqlite3_open([pathDB UTF8String], &database) == SQLITE_OK) { // query per l’inserimento del nuovo giocatore NSString *query = [NSString stringWithFormat:@”INSERT INTO squadre (squadra, nazione) VALUES (‘%@’,’%@’)”,[squadra objectForKey:@”squadra”],[squadra objectForKey:@”nazione”]]; const char *sql = [query UTF8String]; sqlite3_stmt *insert_statement; // eseguiamo la query if(sqlite3_prepare_v2(database, sql, -1, &insert_state-ment, NULL) == SQLITE_OK) { if(sqlite3_step(insert_statement) == SQLITE_DONE) { // ricarichiamo la lista [self caricaValori]; } } // chiudiamo il db sqlite3_finalize(insert_statement); } sqlite3_close(database);}

Questometodoèpraticamenteugualeaquelloperlacancellazionediunelemento,l’unicadifferenzaèancoraunavoltalaquery(riga5).Essaèuna“insert”,incuidob-biamoinserireilnomedellasquadraelasuanazionalità.

Vediamooralarestantepartedaaggiungereall’applicazione.Perprimacosadobbiamodefinireunanuovavista,chechiameremo“AddSquadra-ViewController”.Dalmenù“File->New->NewFile...”escegliamo“UIViewControllersubclass”come tipologia. Inseriamo il nome “AddSquadraViewController”, assicuriamoci che la subclasssia“UIViewController”echel’opzione“WithXIBforUserInterface”siaspuntata.

c a P I t o l o 8S Q L Tu t o r i a l

Page 106: Manuale IOS

106

Apriamoilfile“AddSquadraViewController.xib”eimpostiamolaseguentestrutturagrafica:

Fig. 8.15: Creiamo una nuova vista

Fig. 8.16: Struttura grafica

Oraeseguiamoleconnessioniallaclasse“AddSquadraViewController”.Definiamodueoutletperleduetextfield,eun’azioneperilbottone.

Page 107: Manuale IOS

107

Eccocomelehodefiniteio:

Codice 8.8: File di interfaccia AddSquadraViewController.h

Codice 8.9: synthesize dell’elemento dataList

123456789101112

1234567

#import <UIKit/UIKit.h>#import “Data.h”

@interface AddSquadraViewController : UIViewController

@property (assign, nonatomic) Data *dataList;@property (strong, nonatomic) IBOutlet UITextField *fieldNome;@property (strong, nonatomic) IBOutlet UITextField *fieldNazione;

- (IBAction)addSquadra:(id)sender;

@end

#import “AddSquadraViewController.h”

@implementation AddSquadraViewController

@synthesize dataList;@synthesize fieldNome;@synthesize fieldNazione;

OltreaglielementidiInterfaceBuilder(righe7,8e10)hodefinitoancheunapropertyper“dataList”,checiserviràperfarriferimentoalnostrodatabase,inparticolareallalistadeglielementichegiàèstatadefinita.Notiamochel’argomentoè“assign”:questosignificachenonvienecreatounnuovoelemento(comeaccadeadesempioquandotroviamostrong),masifariferimentoallostesso.Proprioquellocheserveanoi.

Definitalastrutturagraficaedellaclasse,possiamopassareall’implementazionedelcodicenelfile“AddSquadraViewController.m”.Perprimacosainseritelasynthesizedellaproprietà“dataList”(riga5):

c a P I t o l o 8S Q L Tu t o r i a l

Page 108: Manuale IOS

108

Implementiamo, poi, il metodo associato alla pressione del bottone:

Codice 8.10: Implementazione del metodo associato al bottone

Codice 8.11: Aggiunta del bottone per l’inserimento di una squadra

123

45

67891011

121314

12345678

910

- (IBAction)addSquadra:(id)sender { // controlliamo se i campi sono stati inseriti if (([fieldNome.text length] != 0)&& ([fieldNazione.text length] != 0)){ // creiamo un dizionario con i valori NSMutableDictionary *squadra = [[NSMutableDictionary al-loc] initWithObjectsAndKeys:fieldNome.text, @”squadra”, fieldNazio-ne.text, @”nazione”, nil]; // inseriamolo nel db [dataList aggiungiSquadra:squadra]; // torniamo alla lista [self.navigationController popViewControllerAnimated:YES]; } else { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”Attenzione” message:@”Controlla di aver inserito tutti i campi necessari” delegate:nil cancelButtonTitle:@”OK” other-ButtonTitles: nil]; [alert show]; }}

- (void)viewDidLoad { [super viewDidLoad]; // inizializziamo l’oggetto Data dataList = [[Data alloc] init]; // bottone per aggiungere una nuova squadra UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(aggiungiSquadra:)]; self.navigationItem.rightBarButtonItem = addButton;}

Questaazionedeverichiamareilmetodo“aggiungiSquadra”dell’oggettoData,perin-serirelanuovasquadraneldatabase.Primadifareciò,però,vienecontrollatocheiduecampiditestononsianovuoti(riga3),perchènonvogliamoavereundatabasecondelleinconsistenze.Sevienesuperatoilcontrollo,creiamoundizionarioincuiinseriamoiva-loridigitatidall’utente(riga5),epassiamopoiquestooggettoall’elementodataList(riga7),cheinseriràneldatabaselanuovasquadra.Alcontrario,sel’utentenonhainseritotuttiidatinecessarivienemostratounmessaggiodiavvertimento(riga11).Abbiamoquasiconcluso.Noncirestachedefinireunbottonedainserirenellanaviga-tionbarpostasopralatabellainiziale,inmodochel’utentesappiasubitodovepremereperinserireunanuovasquadra.Torniamo,quindi,nelfile“MasterViewController.m”enelmetodo“viewDidLoad”inseriamolaseguentedefinizione(righe8e9):

Page 109: Manuale IOS

109

AbbiamosemplicementedefinitounUIBarButtonItem,ovverounbottoneperlanavi-gationbar,utilizzandolostile“UIBarButtonSystemItemAdd”,chefornisceunostiledidefaultconun“+”comeimmagine.L’oggettocreatovienepoiassegnatoalbottonedidestradellanavigationbar,cheèunaproprietàgiàdisponibile.Albottoneèassociatoilmetodo“aggiungiSquadra:”,chevieneinvocatoquandosipremesullostesso.Eccoladefinizioneditalemetodo:

Codice 8.12: Implementazione del metodo “aggiungiSquadra:”

Codice 8.13: Modifica del metodo “viewWillAppear:”

12

34

5

123456

- (void)aggiungiSquadra:(id)sender{ AddSquadraViewController *addController = [[AddSquadra-ViewController alloc] initWithNibName:@”AddSquadraViewController” bundle:nil]; addController.dataList = dataList; [self.navigationController pushViewController:addController animated:YES];}

- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // ricarichiamo la tabella [self.tableView reloadData];}

Ormaidovrestecapirealvolocosafaquestometodo:semplicementeinizializzaunanuovavista“AddSquadraViewController”,glipassailrifermentodell’oggettodata-Listevienepoimostratasulloschermo.Nullachenonabbiategiàvisto.

Mancasolounpiccolissimoritocco.Nelmetodo“viewWillAppear:”inseritequestaistruzione(riga5):

Essapermettedi ricaricare la tabellaquandovienevisualizzata lavista.Questoènecessarioquandol’utentehainseritounanuovasquadraeritornaallalistaprinci-pale:grazieaquestaistruzionelatabellaverràricaricataeilnuovoinserimentosaràvisibile all’utente.

Abbiamoconcluso!Cliccatesu“Run”etestate lavostraapplicazionepienamentefunzionante!

c a P I t o l o 8S Q L Tu t o r i a l

Page 110: Manuale IOS

110

Fig. 8.17b: App 8 “SQLTutorial”Fig. 8.17a: App 8 “SQLTutorial”

Page 111: Manuale IOS

111

c a P I t o l o 9R S S R e a d e r

9. Creiamo un semplice lettore di feed RSS

LaprimaapplicazionecheandremoarealizzareèunsemplicemautilissimolettoredifeedRSS.Vedremocomeleggereidati(solitamentedegliarticoli)diunfeed,vi-sualizzandoliinunatabella.

Perrealizzarequestosemplice lettoredi feedRSSutilizzeremodiversiaspetticheabbiamogiàanalizzatoneiprecedenticapitoli,inparticolarelagestionedelletabelle(capitolo5)el’utilizzodiXML(capitolo8).Sealcuniaspettidiquestiduetutorialnonvisonodeltuttochiari,viconsigliodiriguardarviiduecapitoliinquestione,inmododanonaverprobleminellacreazionedellettoredifeedRSS.

Parte 1: Creiamo la base del lettore

Creiamo la struttura dell’applicazioneCreiamo un nuovo progetto di tipo “Master Detail Application” e chiamiamolo“RSSReader”.Comesempreassicuriamoci che “Use storyboard”e “IncludeUnitTest”sianodisattivati.Comeabbiamovistonelcapitolo5,questotemplateci for-nisceun’implementazionedibaseperunatabella, incuinoiandremoadinserireivalori letti dal feed RSS.

Iniziamodefinendonellaclasse“MasterViewController.h”glielementichesarannonecessariperlanostraapplicazione:

Codice 9.1: Definizione del file di interfaccia MasterViewController.h

12345

67891011121314151617181920

2122

#import <UIKit/UIKit.h>

@class DetailViewController;

@interface MasterViewController : UITableViewController <NSXMLParser-Delegate>{ // lista di tutti gli elementi letti dal feed NSMutableArray *listaElementi; // variabile temporanea per un singolo elemento NSMutableDictionary *itemCorrente; // variabili temporanee per i singoli campi NSMutableString *elementoCorrente; NSMutableString *titolo; NSMutableString *data; NSMutableString *link; NSMutableString *contenuto;}

- (void)parseRSSFeed:(NSString*)feed;

@property (strong, nonatomic) DetailViewController *detailViewCon-troller;

@end

Page 112: Manuale IOS

112

L’oggettoallariga7conterràtuttiglielementilettidalfeedRSS,chesolitamentesononotizieoarticoli.Talelistasarà,comeormaiavretebenimparato,ildatasourcedellatabella.Glielementidichiaratidallariga11inpoiservirannoalparserperleggeretut-teleinformazionidiunarticoloesalvarleall’internodiundizionario(riga9).Diognielementodelfeed,quindi,leggeremotitolo,datadipubblicazione,linkall’articoloecontenutodell’articolostesso(chepuòessereanchesolounapreviewdellostesso).

Definiamo i metodi del parserSpostiamocinelfile“MasterViewController.m”incuiiniziamoadinserireimetodine-cessaripereseguireilparsingdiunfeedRSS.Iniziamodalmetodo“viewDidLoad”:

Codice 9.3: Implementazione del metodo “parseRSSFeed:”

Codice 9.2: Imlementazione del metodo “viewDidLoad”

12345

6789

10111213141516171819

12345678

- (void)parseRSSFeed:(NSString*)feed{ // inizializziamo la lista degli elementi letti dal feed listaElementi = [[NSMutableArray alloc] init]; // dobbiamo convertire la stringa “feed” in un elemento “NSURL” NSURL *feedURL = [NSURL URLWithString:feed]; // inizializziamo il nostro parser XML NSXMLParser *rssParser = [[NSXMLParser alloc] initWithContentsOfURL:feedURL]; // settiamo alcune proprietà [rssParser setDelegate:self]; [rssParser setShouldProcessNamespaces:NO]; [rssParser setShouldReportNamespacePrefixes:NO]; [rssParser setShouldResolveExternalEntities:NO]; // avviamo il parsing del feed RSS [rssParser parse];}

- (void)viewDidLoad { [super viewDidLoad]; // impostiamo l’indirizzo del feed RSS NSString *path = @”http://feeds.feedburner.com/TheBubiDevs”; // richiamiamo il metodo che avvierà il parser [self parseRSSFeed:path];}

Semplicementeabbiamodefinitounastringaconl’indirizzodelfeedRSSdaleggere,eabbiamopoirichiamatoilmetodochesioccuperàdiinizializzareedavviareilpar-ser,acuivienepassatocomeparametropropriol’indirizzodelfeedRSS.Ditalemetodoabbiamogiàdefinitol’intestazionein“MasterViewController.h”,ve-diamooralasuaimplementazione:

Page 113: Manuale IOS

113

Perprimacosavieneinizializzatalalistachedovràospitareivarielementilettidalfeed (riga3).Successivamente,vieneconvertito l’indirizzoadunoggettoNSURL,comeabbiamogiàvistonelcapitolodedicatoadXML.Ancheladefinizionedell’og-gettorssParserègiàvista,mentrealcuneproprietàchevengonosettatesononuove.Esse sono necessarie per la corretta lettura di un feed RSS, quindi non mi dilungo tropponellalorospiegazione.Allariga18,infine,vieneavviatoilparsingdelfeed.

Comegiàsapete,ildelegatodell’oggettoNSXMLParserrichiedechevenganoimple-mentatialcunimetodiperilcorrettofunzionamentodelparser.Iniziamoinserendoilseguentemetodo:

Codice 9.4: Implementazione del metodo che rileva i nuovi elementi

1

23456789101112

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)ele-mentName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{ elementiCorrente = [elementName copy]; if ([elementName isEqualToString:@”item”]) { // inizializza tutti gli elementi itemCorrente = [[NSMutableDictionary alloc] init]; titolo = [[NSMutableString alloc] init]; data = [[NSMutableString alloc] init]; contenuto = [[NSMutableString alloc] init]; link = [[NSMutableString alloc] init]; }}

Comeabbiamogiàvisto,essovienerichiamatoquandoilparserincontraunnuovoelementonelfilexml.Quandotaleelementocorrispondead“item”significachestaperiniziareunnuovoarticolo(ounanuovanotizia),quindidovrannoessereinizializ-zatetuttelevariabilicheconterrannopoiivaloriletti(adesempioiltitolo,link,etc).

Ilsecondometododainserireèquellochevienerichiamatoquandofiniscelalettu-radiunelementodapartedelparser,ovveroquandosiincontrauntagdichiusura (vedicodice10.5).

c a P I t o l o 9R S S R e a d e r

Page 114: Manuale IOS

114

Inquestocasoivaricampilettivengonosalvatinell’oggettoitemCorrente,chesap-piamoessereundizionario.Adognicampo,quindi,vieneassociataancheunachia-ve, in modo da poter recuperare i singoli valori in modo semplice e veloce.L’oggettoitemCorrente,infine,vieneaggiuntoallalistachecontienetuttiglielementilettidalfeed(riga11).

Per completare il parser ci mancano solo due metodi:

Codice 9.5: Implementazione del metodo richiamato a fine lettura di un elemento

Codice 9.6: Implementazione dei metodi finali del parser

1

234

5678910111213

1

2345678910111213141516

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{ if ([elementName isEqualToString:@”item”]) { // inseriamo tutti i valori letti nell’elemento itemCor-rente [itemCorrente setObject:titolo forKey:@”titolo”]; [itemCorrente setObject:link forKey:@”link”]; [itemCorrente setObject:contenuto forKey:@”contenuto”]; [itemCorrente setObject:data forKey:@”data”]; // inseriamo l’elemento nella lista degli elementi [listaElementi addObject:[itemCorrente copy]]; }}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{; // salva i caratteri per l’elemento corrente if ([elementoCorrente isEqualToString:@”title”]){ [titolo appendString:string]; } else if ([elementoCorrente isEqualToString:@”link”]) { [link appendString:string]; } else if ([elementoCorrente isEqualToString:@”description”]) { [contenuto appendString:string]; } else if ([elementoCorrente isEqualToString:@”pubDate”]) { [data appendString:string]; }}

- (void) parserDidEndDocument:(NSXMLParser *)parser { [self.tableView reloadData];}

Page 115: Manuale IOS

115

Ilprimometodovienerichiamatoognivoltacheunnuovocarattereèrilevatodalpar-ser.Asecondadell’elementochestiamoconsiderando,andremoainserireilnuovocarattere in coda a quelli già letti dello stesso elemento, in modo da ricostruire l’in-formazionecompleta.Adesempio,stiamoconsiderandol’elemento“title”.Vengonoletti,nell’ordine, iseguenticaratteri:“Dev”,“Tutorial”,“#2”.Unendoivaricaratterilettiricostruiremoiltitoloesattodelnostrofeed,ovvero“DevTutorial#2”.

Ilsecondometodo,invece,vienerichiamatosoloquandoilparsercompletalaletturadelfeedRSS:ilparserhacompletatolasuaeleborazione,quindilatabellapuòrica-ricare i propri dati, mostrando gli elementi letti dal feed.

Visualizziamo gli elementi nella tabellaNoncirestacheimpostarelatabellainmodochemostriivarielementicheabbiamoricavato dal feed RSS. Ormai dovreste essere pratici con le table view, quindi eccovi i vari metodi da impostare:

Codice 9.7: Impostazione della tabella

1

2345

678

910

11

12131415

161718

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [listaElementi count];}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @”Cell”; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; cell.accessoryType = UITableViewCellAccessoryDisclosu-reIndicator; }

// Configure the cell. NSMutableDictionary *elemento = [listaElementi objectAtIndex:indexPath.row]; cell.textLabel.text = [elemento objectForKey:@”titolo”]; return cell;}

Questimetodidovresteormaiconoscerlibenissimo.Essinonfannoaltrochepopo-larelatabellautilizzandoglielementicontenutiin“listaElementi”.

Abbiamoconcluso!Clicchiamosu“Run”econtrolliamochelanostraapplicazionefunzionicorrettamente!

c a P I t o l o 9R S S R e a d e r

Page 116: Manuale IOS

116

Fig. 9.1: App 10 Beta “RSSReader”

Page 117: Manuale IOS

117

Parte 2: Miglioriamo la grafica dell’applicazione

Visaretesubitoaccortichelavisualizzazionedeglielementinonèlamigliore:iltitolononvienemostratocompletamente,inoltrenonsarebbemalepotervisualizzarean-cheladatadell’articoloounapartedelcontenutocheabbiamoscaricatodalfeed.Possiamo risolvere questi problemi creando una nostra cella personalizzata, chepossaconteneretutteleinformazionidesiderate.Vedremo,quindi,comecreareunacellapersonalizzatainbaseallenostreesigenze,cheandràpoiacomporrelatabellagià presente.

Creiamo la cella personalizzataIlprocedimentoperlacreazionediunacellapersonalizzatanonècomplicato,peròmeritaattenzioneperchèrichiedediversipassaggidaeffettuare.Iniziamocreandounfilexibvuoto.Perfareciòandiamoin“File”->“New”->“NewFile…”enellascher-matacheappariràspostiamocinellasezione“UserInterface”:

Fig. 9.2: Creazione di una cella personalizzata

Selezioniamol’elemento“Empty”,proseguiamoeselezioniamo“iPhone”comede-vice,continuiamoeinseriamo“FeedCell”comenomeperilfile.Abbiamocosìcreatounfilexibvuotocheconterràpoilanostracellapersonalizzata.Primadidefinirelacomposizionegraficadiquestoelemento,dobbiamocreareunaclas-sechegestiscatalecella.Sempredalmenù“File->New->NewFile...”selezioniamoquestavoltalasezione“CocoaTouch”escegliamol’elemento“Objective-Cclass”.

c a P I t o l o 9R S S R e a d e r

Page 118: Manuale IOS

118

Come nome inseriamo “FeedCell” e selezioniamo “UITableViewCell” nel menù“Subclassof”:

Fig. 9.3: Creazione della classe per la cella personalizzata

Abbiamocosìcreatoanchelaclassechedevegestire lanostracella. Iniziamoadimplementareproprioquestaclasse,definendoglielementinecessari.Apriamoilfile“FeedCell.h”einseriamoilseguentecodice:

Codice 9.8: Definizione del file di interfaccia FeedCell.h

12345678910111213

#import <UIKit/UIKit.h>

@interface FeedCell : UITableViewCell { UILabel *labelTitolo; UILabel *labelContenuto; UILabel *labelData;}

@property (nonatomic, strong) IBOutlet UILabel *labelTitolo;@property (nonatomic, strong) IBOutlet UILabel *labelContenuto;@property (nonatomic, strong) IBOutlet UILabel *labelData;

@end

Page 119: Manuale IOS

119

Comevedreteabbiamosemplicementedefinitotre label,chedovrannocontenerelevarieinformazionideglielementilettidalfeed.Diognilabelèdefinitaancheunaproperty,cheovviamentenecessitadellarelativasynthesizenelfile“FeedCell.m”:

Codice 9.8: Inserimento delle synthesize

Codice 9.9: Modifica della classe MasterViewController

1234567

123456

78910111213141516171819202122232425

2627

#import “FeedCell.h”

@implementation FeedCell

@synthesize labelTitolo;@synthesize labelContenuto;@synthesize labelData;

#import <UIKit/UIKit.h>#import “FeedCell.h”

@class DetailViewController;

@interface MasterViewController : UITableViewController <NSXMLParser-Delegate>{ // lista di tutti gli elementi letti dal feed NSMutableArray *listaElementi; // variabile temporanea per un singolo elemento NSMutableDictionary *itemCorrente; // variabili temporanee per i singoli campi NSMutableString *elementoCorrente; NSMutableString *titolo; NSMutableString *data; NSMutableString *link; NSMutableString *contenuto; // cella personalizzata FeedCell *itemCell;}

- (void)parseRSSFeed:(NSString*)feed;

@property (strong, nonatomic) IBOutlet FeedCell *itemCell;@property (strong, nonatomic) DetailViewController *detailViewCon-troller;

@end

Primadidedicarcialladefinizionegraficadellacella,dobbiamoinserireun’ulterioredefinizioneviacodice.Questavoltadobbiamoaprireilfile“MasterViewController.h”emodificarlonelseguentemodo:

c a P I t o l o 9R S S R e a d e r

Page 120: Manuale IOS

120

SemplicementeabbiamodefinitounelementodellaclasseFeedCell(riga19),checiserviràperpopolarelatabella.C’èanchelarelativaproperty(riga24)el’importdellaclassedefinitapocofa(riga2).Nelfile“MasterViewController.m”,ovviamente,dovre-teancheinseritelasynthesizedell’elemento“itemCell”appenadefinito.

Definiamo la grafica della cellaPossiamooradedicarcialladefinizionegraficadellacella.Apriamoilfile“FeedCell.xib”einseriamoalsuointernounelemento“TableViewCell”:

Fig. 9.4: Inserimento di “Table View Cell”

Questa sarà la vista della nostra cella, in cui inseriremo tutti gli elementi necessari. Primadiognialtramodifica,andiamonel“SizeInspector”emodifichiamol’altezzadellacellaalvaloredi130,inmododaaveresufficientespazioadisposizioneperinserire tutti i componenti:

Fig. 9.5: Altezza cella

Page 121: Manuale IOS

121

Andiamo,poi, in“Attributes Inspector”enelcampo“Identifier” inseriamo ilnome“FeedCell”:

Fig. 9.6: Inserimento nom

e

Fig. 9.7: Struttura della cella

Fig. 9.8: Classe FeedCell

Ora inseriamo le varie label necessarie. Esse dovranno contenere, rispettivamente, il titolodellanotizia,ladatadipubblicazioneeunabrevepartedelcontenuto,unasor-ta di preview dell’articolo stesso. Disponetele all’interno della vostra cella secondo i vostrigustielevostrenecessità.Iohoimpostatolaseguentestruttura:

Lelabelperiltitoloeilcontenutopossonocontenereduelineeditesto,quindihoimpostatoanchelarelativaproprietà(comegiàvistonelcapitolo6).

NoncirestachecollegareivaricomponentiaglioggettidefinitinellaclasseFeedCell.Per fareciòselezioniamo la tableviewcelleandiamo in “Identity Inspector”.Nelcampo“Class”scegliamo“FeedCell”comeclasse:

c a P I t o l o 9R S S R e a d e r

Page 122: Manuale IOS

122

Oraspostiamocinel“ConnectionInspector”ecolleghiamoglielementicheabbiamode-finitoinprecedenzaconlecorrettelabel.Nelmiocaso,quindi,ilrisultatosaràilseguente:

Fig. 9.9: Connessioni

Tuttipassaggisemplicicheabbiamogiàvistoneiprecedenticapitoli.Percompletareladefinizionediquestacelladobbiamocollegarel’elementoitemCellcheabbiamodefinitonellaclasseMasterViewController.Perfarciò,abbiamobiso-gnochetaleclassesiailFile’sOwnerdellacellapersonalizzata.Selezioniamo,quin-di,ilFile’sOwnerdellacella,spostiamociin“IdentityInspector”enelcampo“Class”scegliamo“MasterViewController”comeclasse:

Fig. 9.10: Classe MasterViiewController per il File’s Owner

Fattociò,noncirestacheandarenel“ConnectionsInspector”ecollegarel’oggetto“itemCell”conlanostratableviewcell:

Fig. 9.11: Collegam

ento

Siamofinalmenteprontiperutilizzarequestacellapersonalizzatanellanostraapplicazione!

Page 123: Manuale IOS

123

Utilizziamo la cellaPrimadivedereilcodicenecessarioperutilizzarelanuovacella,dobbiamofareunapiccolissimamodificaallatabellaoriginale:dobbiamoaumentareladimensionedellecelle, altrimenti tutto il layout verrà sballato. Apriamo il file “MasterViewController.xib” e selezioniamo la tabella. Andiamo nel“SizeInspector”enelcampo“RowHeight”inseriamoilvalore130,proprioladimen-sionecheabbiamosceltoperlacellapersonalizzata:

Fig. 9.12: Modifica dell’altezza nella tabella

Possiamosalvareespostarcinelfile“MasterViewController.m”.L’unicometodochedovremomodificaresaràquellochesioccupadiimpostareilcontenutodellevariecelle,ovvero“tableView:cellForRowAtIndexPath:”.DovretemodificarlocomevedeteinCodice10.10propostonellapaginasuccessiva.

c a P I t o l o 9R S S R e a d e r

Page 124: Manuale IOS

124

Diversamente dalle altre volte in cui abbiamo lavorato con le table view, questa volta vieneinizializzatounoggettoditipoFeedCell(riga4),chevienepoiassociatoall’og-gettoitemCell.Questofasichevengacaricatalanostranuovacellapersonalizzatadirettamentedalfilexibcheabbiamodefinito.Laconfigurazionedellacella,poi,èdavverosemplice:ognilabelvienerichiamatacomeuna normale proprietà dell’oggetto cell, e viene impostato il contenuto desiderato. Nelcasodellapreviewdell’articololimitiamoicaratteridavisualizzarea80,pernonoccupare troppa memoria inutilmente.L’oggetto data, volendo, potrebbe essere convertito in un formato a noi più familiare, adesempionellaformadd/MM/yyyy.

Abbiamoconcluso!Clicchiamosu“Run”etestiamoilnostrolettoredifeedmoltopiùprofessionale!

Codice 9.10: Modifica del metodo “UITableViewCell”

1

234

567

8

910111213

1415

16171819

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @”FeedCell”; FeedCell *cell = (FeedCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { // carichiamo il nib della cella e assegniamolo alla cella corrente [[NSBundle mainBundle] loadNibNamed:@”FeedCell” owner:self options:NULL]; cell = itemCell; }

// Configure the cell. NSMutableDictionary *elemento = [listaElementi objectAtIndex:indexPath.row]; cell.labelTitolo.text = [elemento objectForKey:@”titolo”]; cell.labelContenuto.text = [[elemento objectForKey:@”contenuto”] substringToIndex:80]; cell.labelData.text = [elemento objectForKey:@”data”];

return cell;}

Page 125: Manuale IOS

125

Fig. 9.13: App 10 Beta “RSSReader”

c a P I t o l o 9R S S R e a d e r

Page 126: Manuale IOS

126

Parte 3: Visualizziamo l’articolo completo

Per rendere davvero completo il nostro lettore di feed RSS ci manca una semplice funzione:vogliamochequandol’utenteselezionaunarticolo,essovengacaricatoall’internodiunanuovavista(ovviamenteverràcaricatalapaginawebrelativaall’ar-ticolo in questione).

Per fare ciò, iniziamomodificando il file “DetailViewController.xib”, che sappiamoesserelavistachevieneapertaquandol’utenteselezionaunarigadellatabella.

Cancelliamo la label presente e inseriamo al suo posto una web view:

Fig. 9.14: Inserimento della web view

Creiamo il collegamento (outlet) tra l’oggetto e la classe “DetailViewController.h”,come abbiamo già fatto numerose volte. Chiamiamoquestooggetto“webView”.

Page 127: Manuale IOS

127

Ecco come deve essere la vostra classe:

Codice 9.11: File di interfaccia DetailViewController.h

Codice 9.12: Implementazione del metodo “configureView”

12345678

910

1234567

891011

#import <UIKit/UIKit.h>

@interface DetailViewController : UIViewController

@property (strong, nonatomic) id detailItem;

@property (strong, nonatomic) IBOutlet UIWebView *webView;@property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLa-bel;

@end

- (void)configureView { // Update the user interface for the detail item.

if (self.detailItem) { NSURL *url = [NSURL URLWithString:self.detailItem]; // creiamo una richiesta per la pagina NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // visualizziamo la richiesta (la pagina) nella web view [self.webView loadRequest:request]; }}

Volendopoteteeliminarel’oggetto“detailDescription”,inquandononèpiùutilizzato(senonloeliminatenonc’ènessunproblema).

Oradobbiamospecificareilcodicechesioccuperàdimostrarel’articolocompletonellawebview,usando lostessoprocedimentocheabbiamovistonelcapitolo4. Nelfile“DetailViewController.m”inseriamo,quindi,questocodicenelmetodo“con-figureView”:

Leistruzionisonoesattamentelestessecheabbiamogiàvisto.L’elementocheutiliz-zeremoperpassareillinkdell’articoloè“detailItem”,cheègiàpresentenellaclasse,echeabbiamogiàconosciutonelcapitolo5.

L’ultimacosadafareèinserireproprioilcodicechesioccupadipassareillinkallavista di dettaglio.

Nelfile“MasterViewController.m”modifichiamoilmetodocomepropostoinCodice10.13 nella pagina successiva.

c a P I t o l o 9R S S R e a d e r

Page 128: Manuale IOS

128

Anchequestometododovrestegiàconoscerlo.Dopoaver inizializzato la vistadidettaglio, ricaviamo il linkdell’articoloselezionatodall’utente (riga7), lo ripuliamodaeventualicaratterichenonfannopartedell’urlveroeproprio(adesempiospazi,tabulazioni,etc)elopassiamoinfineallavistadidettaglio,usandolaproprietà“de-tailItem”.Cosìfacendolavistacaricheràlapaginawebdesideratadall’utente.

Lanostraapplicazioneèdavveropronta!Possiamocliccaresu“Run”egoderci ilnostrolettoredifeedRSScompletodituttelefunzioni!

Codice 9.13: Passiamo il link dell’articolo da visualizzare

1

23

4567

89

10

11

12131415

16

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (!self.detailViewController) { self.detailViewController = [[DetailViewController al-loc] initWithNibName:@”DetailViewController” bundle:nil]; } // ricaviamo il link dell’elemento selezionato NSString *linkDaAprire = [[listaElementi objectAtIndex:indexPath.row] objectForKey: @”link”]; // ripuliamo il link da spazi, return e tabs linkDaAprire = [linkDaAprire stringByReplacingOccurrence-sOfString:@” “ withString:@””]; linkDaAprire = [linkDaAprire stringByReplacingOccurrencesOfString:@”\n” withString:@””]; linkDaAprire = [linkDaAprire stringByReplacingOccurrence-sOfString:@” “ withString:@””]; // passiamo il link alla vista di dettaglio self.detailViewController.detailItem = linkDaAprire; [self.navigationController pushViewController:self.detail-ViewController animated:YES];}

Page 129: Manuale IOS

129

Fig. 9.15b: App 10 “RSSReader”Fig. 9.15a: App 10 “RSSReader”

c a P I t o l o 9R S S R e a d e r

Page 130: Manuale IOS

130

Page 131: Manuale IOS

131

c a P I t o l o 1 0M y B r u s h e s

10. Realizziamo il nostro “Brushes”

Quellochehopensatopervoiinquestocapitoloèunpo’particolare,peròèsicuramenteuntutorialmoltocarinoeconmoltecoseutili.SicuramentetuttivoiconoscereteBrushes,unprogramma,disponibilenell’AppStore,moltofamosoperdisegnaresulproprioiPho-nee iPodTouch.Hopensato,quindi,dispiegarvicomerealizzarneunotuttovostro! Realizzeremounavistacheconterràla“tavolagrafica”,ovverolaparteincuil’utentepotràdisegnare.Cisarà,poi,unasecondavistaincuiinseriremoleimpostazioni,perpermettereall’utentedicambiareilcoloreeladimensionedelpennello.Infinevedremocomefareinmodochel’utentepossasalvareipropridisegninelrullinofotograficodiiOS.

Parte 1: Creiamo la tavola grafica

Inquestaprimapartevedremocomefareinmodochel’utentepossa,muovendoilditosulloschermo,disegnareasuopiacimento.Perquestaapplicazionesfrutteremoiltemplate“UtilityApplication”,checipermettediaveregiàdueviste,inmododarisparmiare un po’ di lavoro.

Creiamo la struttura graficaCreiamounnuovoprogettoditipo“UtilityApplication”echiamiamolo“MyBrushes”.Comesempreassicuriamociche“Usestoryboard”e“IncludeUnitTest”sianodisattivati.Lastrutturacheabbiamoselezionatocimetteadisposizionedueviste:un“Main-ViewController”cheèquellacheappareinizialmente,eun“FlipsideViewController”,cheapparesevienepremuto ilpulsante“i” (info),conun’animazionegiàdefinita.Questedueviste,quindi,potremosfruttarlepercrearelanostraapplicazione:nella“MainView”creeremolazonaincuil’utentepotràdisegnare,mentrenella“Flipside-View”inseriremoleimpostazioni(quindiilcoloredelpennello,ladimensione,etc).Apriamoilfile“MainViewController.xib”,avremounavistacomequesta:

Fig. 10.1: MainV

iewC

ontroller.xib

Page 132: Manuale IOS

132

Dobbiamomodificarneunpo’l’aspetto.Iniziamoscegliendocomecoloredisfon-doilbianco(lofatesemplicementedalpannello“AttributesInspector”).Cancellate,inoltre,ilbottone“i”cheèpresentenell’angolobassodestrodellavista.

Inserendosulfondodellavistauna“Toolbar”.Iohomessocomestiledellatoolbar“BlackTranslucent”,ovviamentevoipotetefarlacomepreferite.Inserite,inoltre,duebottoni“BarButtonItem”eun“FlexibleSpaceBarButtonItem”traidue.Ilprimobottonerinominateloin“Cancella”mentreilsecondoin“Impostazioni”.Ecco come si presenta per ora la vista:

Fig. 10.2: Struttura grafica m

odificataFig. 10.3: S

truttura grafica completa

Fattociò,dobbiamoinserireunaimageviewinmodocheoccupituttalavista:

Page 133: Manuale IOS

133

Questa sarà l’area in cui l’utente potrà disegnare.

Dobbiamooracreare i collegamenti traquestioggetti e laclasse “MainViewCon-troller”.Comesempreapriamol’”AssistantEditor”ecreiamounoutletper la ima-geview,chiamandolo“viewDisegno”.Creiamoun’azioneperilbottone“Cancella”,chiamandola“cancellaDisegno”.Seaveteeseguitotuttocorrettamentelavostraclassesaràcosìdefinita:

Codice 10.1: File di interfaccia MainViewController.h

123

45678910

#import “FlipsideViewController.h”

@interface MainViewController : UIViewController <FlipsideViewCon-trollerDelegate>

@property (strong, nonatomic) IBOutlet UIImageView *viewDisegno;

- (IBAction)cancellaDisegno:(id)sender;- (IBAction)showInfo:(id)sender;

@end

Per ilbottone“Impostazioni”, invece, riutilizziamo l’azione“showInfo”cheeragiàstatadefinita.Percollegarlacon ilnostrobottonevibasteràutilizzare ilcerchiettochevedeteafiancodelnomedelmetodo:

Fig. 10.4: Collegamento bottone - metodo

c a P I t o l o 1 0M y B r u s h e s

Page 134: Manuale IOS

134

Prendeteloecollegateloconilbottone,edilgiocoèfatto!Abbiamocosìconclusoladefinizionedell’interfacciagrafica,possiamodedicarciallascritturadelcodice.

Definiamo i metodi necessariApriamoilfile“MainViewController.h”,dobbiamodefinirealcunielementicheciser-viranno nel nostro programma. Ecco il codice da aggiungere:

Codice 10.2: Definizione degli elementi necessari

123

45678910111213141516

#import “FlipsideViewController.h”

@interface MainViewController : UIViewController <FlipsideViewCon-trollerDelegate> { // ultimo punto salvato CGPoint ultimoPunto; // parametri del pennello float dimensionePennello; UIColor *colorePennello;}

@property (strong, nonatomic) IBOutlet UIImageView *viewDisegno;

- (IBAction)cancellaDisegno:(id)sender;- (IBAction)showInfo:(id)sender;

@end

Analizziamoglielementicheabbiamoappenainserito.Allariga5abbiamodefinitounoggettoCGPoint,chenonèaltrocheuncontenitoredelleduecomponentidiunpunto: le coordinate x e y. Questo ci servirà per sapere il punto precedente a quello considerato,permettendocicosìditracciareunalinea.Allariga7e8definiamolecaratteristichedelpennello:dimensioneecolore.Ladimensioneèunavariabileditiporeale(float),mentreilcoloreèdefinitodaltipoUIColor,cheinizializzeremoconlostandardRGB.

Questesonoleunichedichiarazionidicuiabbiamobisogno.Salviamoquindiquestofileespostiamociin“MainViewController.m”.Leazionichedovremodefiniresarannodaimplementarein3metoditipicidellagestionedelmultitouch:

•touchesBegan,richiamatoquandosiiniziaunmovimento.Dovremoricavareilpun-toincuideveiniziareildisegno;

•touchesMoved,richiamatoquandounmovimentoèincorso.Ognivoltachevieneeseguitodevedisegnareunsegmentocolorato,inmodocheappaiaunalinearaf-figuranteildisegnodell’utente;

•touchesEnded,metodorichiamatoquandoilmovimentoèterminato.Inparticolareserve quando l’utente compie solo un singolo tap, disegnando così un semplice punto.

Page 135: Manuale IOS

135

Iniziamo,quindi,ascrivereilcodicenecessario.Iniziamoconilmetodo“viewDidLoad”:

Codice 10.3: Definizione del metodo “viewDidLoad”

Codice 10.4: Definizione del metodo “touchesBegan:”

12345

6

12345

- (void)viewDidLoad { [super viewDidLoad]; // settimo i valori di default del pennello dimensionePennello = 5.0; colorePennello = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0];}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // ricaviamo l’ultimo punto toccato dall’utente UITouch *touch = [touches anyObject]; ultimoPunto = [touch locationInView:viewDisegno];}

Ilsuocompitoèmoltosempliceechiaro:vieneimpostataladimensionestandarddelpennelloa5.0(pixel)euncolore,inquestocasoilrosso.LadefinizionedelcoloreavvieneimpostandolecomponentiRGB,ovveroRed(rosso),Green(verde)eBlue(blu):variandolequantitàconunvalorecompresoda0.0a1.0otterremotuttiicoloriammessi da questo sistema. Il campo alpha, invece, rappresenta la trasparenza.Fatequalcheprovaperprendereconfidenzaconquestosistema!

Ilsecondometodocheandremoadefinireè“touchesBegan”.Lasuaimplementa-zioneèmoltosemplice,dobbiamosoloricavareilpuntodiiniziodelmovimento.Ecco il metodo da inserire:

Comevedeteèmoltosemplice:dall’oggettotouchsiricavailpunto(sempredefinitocomeCGPoint),chevieneassegnatoall’oggetto“ultimoPunto”(riga4).Èimportantespecificare“viewDisegno”comeparametrodellafunzione“locationIn-View”, altrimenti ricaverete tocchi relativi anche ad altre parti dello schermo, cheperòanoinoninteressano.

Passiamooraalladefinizionedelmetodopiù impegnativoe importante: “touche-sMoved”,chetrovereteinCodice11.5nellapaginasuccessiva.

c a P I t o l o 1 0M y B r u s h e s

Page 136: Manuale IOS

136

Iniziamoadanalizzarepassopassoilcodicecheabbiamoappenascritto.Allariga7troviamoladefinizionediun“GraphicsContexts”.QuestoèunaspettocomplessodelCoreGraphics,mautilizzandoquestafunzioneloadattiamosempli-cementeallanostraUIImageView,cheinfattiglipassiamocomeparametro.Questocipermetteràdidisegnareall’internodellanostraimmagine.Conl’istruzioneseguen-te,infatti,definiamol’areaincuipotremodisegnare:essaavràlastessadimensionedell’immagine“viewDisegno”.Lerighe10e11siriferisconoalladefinizionedel“pennello”,concuil’utentedise-gneràsulloschermo.Prima,infatti,vieneimpostatalaforma(inquestocaso“kCGLi-neCapRound”èdiformacircolare,mapossiamoanchefarloquadratootriangolare,vibastaguardareladocumentazionepervedereglialtrivaloripossibili),poiladimen-sione,passandoovviamentelavariabile“dimensionePennello”,checontieneproprioilvaloredesiderato(riga11).Lerighe13e14servonoperimpostareilcolorealnostropennello.AbbiamovistoprimacheilcoloreèdefinitodaunelementoUIColor.PurtroppodobbiamoconvertirelevariecomponentiinCGFloat,el’unicomodochehotrovatoèquellochevedetenelcodice.

Codice 10.5: Definizione del metodo “touchesMoved:”

12345678

910

11

1213

14

151617

18

192021

22232425

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint puntoCorrente = [touch locationInView:viewDisegno]; // definiamo il contest grafico UIGraphicsBeginImageContext(viewDisegno.frame.size); [viewDisegno.image drawInRect:CGRectMake(0, 0, viewDisegno.frame.size.width, viewDisegno.frame.size.height)]; // settiamo la forma e la dimensione del pennello CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCa-pRound); CGContextSetLineWidth(UIGraphicsGetCurrentContext(), dimensio-nePennello); // convertiamo il colore e impostiamolo come colore del pennello const CGFloat *components = CGColorGetComponents([colorePennello CGColor]); CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), com-ponents[0], components[1], components[2], components[3]); // disegna il percorso CGContextBeginPath(UIGraphicsGetCurrentContext()); CGContextMoveToPoint(UIGraphicsGetCurrentContext(), ultimoPunto.x, ultimoPunto.y); CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), puntoCorrente.x, puntoCorrente.y); CGContextStrokePath(UIGraphicsGetCurrentContext()); // settiamo il disegno appena creato viewDisegno.image = UIGraphicsGetImageFromCurrentImageCon-text(); UIGraphicsEndImageContext(); ultimoPunto = puntoCorrente; }

Page 137: Manuale IOS

137

Primaconvertiamol’elemento“colorePennello”inunarrayditipoCGFloat(riga13),poipassiamolevariecomponentiall’istruzionechesettailcoloredelpennello(riga14).Lerighedalla16alla19sonoquellechesioccupanodeldisegnoveroepropriodellalinea.Partendoda“ultimoPunto”finoa“puntoCorrente”vienedisegnatounalineachecomporràpoiiltrattovolutodall’utente.Lerighe21e22settanoildisegnocheèstatocreatonell’immagine“viewDisegno”,rendendola così visibile all’utente.Comevedetenonèpoicosìcomplicatoilcodice,peròbisognafareattenzioneanondimenticare nulla.

Mancapocoperterminarelaprimapartedelnostroprogramma!Dobbiamodefini-re ilmetodo“touchesEnded:”.Essodovràesattamentefare lestessecosechefailmetodo “touchesMoved:”. Potremmoanche non implementare questometodo,peròincasodisingolotapnonsuccederebbeniente,mentrenoivogliamodisegnareunsingolopunto.Ovviamentepotetepersonalizzarequestoaspetto,decidendovoil’azionedacompiere.Eccoilcodicedainseriresevoletecheadunsingolotapvengadisegnatounpunto:

Codice 10.6: Codice per disegnare un singolo punto

Codice 10.7: Implementazione del metodo “cancellaDisegno:”

1234

123

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // disegniamo un solo punto [self touchesMoved:touches withEvent:event];}

- (IBAction)cancellaDisegno:(id)sender { viewDisegno.image = nil;}

Comevedetenonfacciamoaltrocherichiamareilmetodo“touchesMoved:”,davve-ro semplicissimo.

L’ultimacosadafareèl’implementazionedelmetodo“cancellaDisegno:”,chetrove-retegiàdefinitonellaclasse.Lasuaimplementazioneèmoltosemplice:percancel-laretuttociòchel’utentehadisegnatobastaporrea“nil”l’immagine:

Abbiamocompletatoquestaprimaparte!Clicchiamosu“Run”etestiamoilnostroBrushes!

c a P I t o l o 1 0M y B r u s h e s

Page 138: Manuale IOS

138

Fig. 10.5: App 11 “MyBrushes”

Page 139: Manuale IOS

139

Parte 2: Inseriamo le impostazioni

In questa seconda parte aggiungeremo la possibilità di cambiare la dimensione e il coloredelpennello,tramiteadun’appositavistadedicataalleimpostazioni.

Creiamo la struttura graficaIniziamoaprendoilfile“FilpsideViewController.xib”:quidovremoinserireicomponentiperpermettereall’utentedipoterselezionareuncoloreeladimensionedelpennello. Ricreate, quindi, una struttura come quella qui proposta:

Fig. 10.6: Struttura grafica im

postazioni

Comepotetevedere,ciservirannotresliderpercambiareilcoloredelpennello(piùunoperlatrasparenza,“alpha”),unaimageviewincuimostreremoilcolorecorrente,inmodochel’utentepossasubitovisualizzarequalecolorestaselezionando,unoslider e una label per la dimensione del pennello.

Dobbiamoancheimpostaredeivalorimassimieminimideivarislider.Selezioniamoilprimoslider(quelloperilrosso),spostiamociin“AttributesInspector”econtrolliamochecome“MinumumValue”siaimpostato“0”,mentrecome“MaximumValue”cisia“1”:

Fig. 10.7: Valori slider colore

c a P I t o l o 1 0M y B r u s h e s

Page 140: Manuale IOS

140

Controllatecheancheirestantisliderdedicatialcoloreabbianoglistessivalorimas-simi e minimi. Per lo slider della dimensione, invece, dobbiamo impostare dei valori diversi.Iohoscelto1comeminimo,e25comemassimo.Ovviamentepotetevariarecome volete questi valori, magari effettuando delle prove.

Fig. 10.9: Azione cambiaColore

Fig. 10.8: Valori slider dimensione

Dobbiamooracreare icollegamenti traquestielementie laclasse“FlipsideView-Controller.h”,comeabbiamosemprefatto.Createglioutletdeiquattrosliderperilcolore, dell’image view, dello slider per la dimensione e della sua label. Le property appenadefinitedovrebberoesserecomeleseguenti:

Codice 10.8: Property definite

1234567

@property (strong, nonatomic) IBOutlet UISlider *sliderRosso;@property (strong, nonatomic) IBOutlet UISlider *sliderBlu;@property (strong, nonatomic) IBOutlet UISlider *sliderVerde;@property (strong, nonatomic) IBOutlet UISlider *sliderAlpha;@property (strong, nonatomic) IBOutlet UIImageView *viewColore;@property (strong, nonatomic) IBOutlet UILabel *labelDimensione;@property (strong, nonatomic) IBOutlet UISlider *sliderDimensione;

Ciservonoanchedueazioni:unachemodifichiilcolorenellaimageviewquandol’u-tentemuoveunodeglislider,l’altrocheaggiornilalabeldelladimensionedelpennello. Partendodalprimoslider(quelloperilcolorerosso)creiamoun’azionechiamandola“cambiaColore”eassociandolaall’evento“ValueChanged”:

Page 141: Manuale IOS

141

Lastessaazionedeveancheesserecollegataaglialtrislider(blu,verdeealpha).Perfareciòutilizziamoilpallinoafiancodelnomedell’azione,comeabbiamovistonelparagrafoprecedente.Unavoltacollegateleazioniaivarislider,possiamocontrollarediaverese-guitoicollegamentiinmanieracorrettaspostandocinel“ConnectionsInspector”:

Fig. 10.10: Collegamenti

Completiamo creando anche un’azione collegata allo slider della dimensione delpennello, chiamando l’azione “cambiaDimensione”.Se avete eseguito tutti i pas-saggiinmanieracorrettalavostraclasse“FlipsideViewController”saràcosìdefinita:

Codice 10.9: File di interfaccia FlipsideViewController.h

123456

7891011

12131415161718192021222324

#import <UIKit/UIKit.h>

@class FlipsideViewController;

@protocol FlipsideViewControllerDelegate- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;@end

@interface FlipsideViewController : UIViewController

@property (weak, nonatomic) IBOutlet id <FlipsideViewControllerDele-gate> delegate;@property (strong, nonatomic) IBOutlet UISlider *sliderRosso;@property (strong, nonatomic) IBOutlet UISlider *sliderBlu;@property (strong, nonatomic) IBOutlet UISlider *sliderVerde;@property (strong, nonatomic) IBOutlet UISlider *sliderAlpha;@property (strong, nonatomic) IBOutlet UIImageView *viewColore;@property (strong, nonatomic) IBOutlet UILabel *labelDimensione;@property (strong, nonatomic) IBOutlet UISlider *sliderDimensione;

- (IBAction)done:(id)sender;- (IBAction)cambiaColore:(id)sender;- (IBAction)cambiaDimensione:(id)sender;

@end

c a P I t o l o 1 0M y B r u s h e s

Page 142: Manuale IOS

142

Scriviamo il codice necessarioPrima di implementare il codice dei varimetodi, dobbiamo definire nel file “Flip-sideViewController.h”unpaiodielementicheciserviranno.Eccoledichiarazionidainserire:

Codice 10.10: Definizione degli elementi

123456

789101112131415

16171819202122232425262728293031

#import <UIKit/UIKit.h>

@class FlipsideViewController;

@protocol FlipsideViewControllerDelegate- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;@end

@interface FlipsideViewController : UIViewController { // proprietà del pennello UIColor *colorePennello; float dimensionePennello;}

@property (weak, nonatomic) IBOutlet id <FlipsideViewControllerDele-gate> delegate;@property (strong, nonatomic) IBOutlet UISlider *sliderRosso;@property (strong, nonatomic) IBOutlet UISlider *sliderBlu;@property (strong, nonatomic) IBOutlet UISlider *sliderVerde;@property (strong, nonatomic) IBOutlet UISlider *sliderAlpha;@property (strong, nonatomic) IBOutlet UIImageView *viewColore;@property (strong, nonatomic) IBOutlet UILabel *labelDimensione;@property (strong, nonatomic) IBOutlet UISlider *sliderDimensione;// proprietà del pennello@property (strong, nonatomic) UIColor *colorePennello;@property (nonatomic, assign) float dimensionePennello;

- (IBAction)done:(id)sender;- (IBAction)cambiaColore:(id)sender;- (IBAction)cambiaDimensione:(id)sender;

@end

Allerighe11e12abbiamodefinito leduecaratteristichedelpennellochevoglia-mopotermodificare: ilcoloree ladimensione.Perentrambeabbiamoanchede-finito le rispettive property (righe 24 e 25), in modo da poterle impostare anchedalla vista principale. Questi due valori li passeremo direttamente dalla “Main-View”,quindiè importantechecisiano ledueproprietà impostatecorrettamente. Passeremoiduevaloriinmodoche,all’aperturadelpannelloperlaloromodifica,l’u-tentetroviivaloricorrentichestautilizzando(quindicoloreedimensioneattuali).

Passiamonelfile“FlipsideViewController.m”einiziamoinserendoleduesynthesizedelleduepropertyappenadefinitecomeinCodice10.10nellapaginasuccessiva.

Page 143: Manuale IOS

143

Iniziamodefinendoilmetodo“viewDidLoad”:

Codice 10.11: Definizione del metodo “viewDidLoad”

Codice 10.12: Definizione delle azioni collegate agli slider

1234

5678910

1112

123

45678

9

- (void)viewDidLoad { [super viewDidLoad]; // settiamo gli elementi con il valore attuale del pennello const CGFloat *components = CGColorGetComponents([colorePennello CGColor]); [self.sliderRosso setValue:components[0]]; [self.sliderVerde setValue:components[1]]; [self.sliderBlu setValue:components[2]]; [self.sliderAlpha setValue:components[3]]; [self.viewColore setBackgroundColor:colorePennello]; self.labelDimensione.text = [NSString stringWithFormat:@”%f”,dimensionePennello]; [self.sliderDimensione setValue:dimensionePennello];}

- (IBAction)cambiaColore:(id)sender { // impostiamo il colore nella image view [self.viewColore setBackgroundColor:[UIColor colorWithRed:self.sliderRosso.value green:self.sliderVerde.value blue:self.sliderBlu.value alpha:self.sliderAlpha.value]];}

- (IBAction)cambiaDimensione:(id)sender { // impostiamo la label con la dimensione del pennello self.labelDimensione.text = [NSString stringWithFormat:@”%f”,self.sliderDimensione.value];}

In questometodo inizializziamo i componenti grafici ai valori attuali del pennello.All’avviodell’applicazionetalivalorisarannorossoperilcoloree5.0perladimensione.

Questivalori,però,potrannoesserevariatidall’utente,quindiènecessariocheognivoltachevieneapertalavistadelleimpostazioniessisianoimpostaticorrettamente.Inparticolare,ricaviamodalcolorelevariecomponenti(comeabbiamogiàvistonellaprimapartedeltutorial),esettiamoilvaloredeglislider(righe5-8).

Allariga9impostiamoilcoloredellaimageview,checimostreràcosìilcoloredelnostro pennello. Leultimeduerighe,infine,servonoperricavareladimensionedelpennelloeinserirlanella label predisposta.

Dobbiamooradefinireledueazionicollegateaglislider.Eccoiduemetodi(davverosemplici) da implementare:

c a P I t o l o 1 0M y B r u s h e s

Page 144: Manuale IOS

144

Ilprimometodo(“cambiaColore:”)nonfaaltrocheleggereivalorideglislidereset-tare lo sfondo dell’immagine con l’UIColor corrispondente. Il secondo metodo lavora nellostessomodo,solamentechevisualizzailvaloredellosliderdelladimensionedelpennello.Semplicivero?

Cimancasolounamodificaadunmetodogiàesistente.Dobbiamo,infatti,passareallaclasse“MainViewController” inuovivaloridelladimensioneedelcoloredelpennello.Modifichiamo,quindi,ilmetodo“done”nelseguentemodo:

Codice 10.13: Modifica del metodo “done:”

Codice 10.14: Modifica dell’intestazione del metodo

123

4

5

12

3

- (IBAction)done:(id)sender { dimensionePennello = self.sliderDimensione.value; colorePennello = [UIColor colorWithRed:self.sliderRosso.value green:self.sliderVerde.value blue:self.sliderBlu.value alpha:self.sliderAlpha.value]; [self.delegate flipsideViewControllerDidFinish:self nuovoColore:colorePennello nuovaDimensione:dimensionePennello];}

@protocol FlipsideViewControllerDelegate- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller nuovoColore:(UIColor*)colore nuovaDimensione:(float)di-mensione;@end

Abbiamo semplicemente letto il valore della dimensione e del colore del pennello, per poipassarloalmetodo“flipsideviewControllerDidFinish”,cheabbiamoopportunamen-temodificato(infattivedretechecisonodeinuoviparametricheglivengonopassati).Torniamoalfile“FlipsideViewController.h”emodifichiamoanche l’intestazionedelmetodochetroviamonell’iniziodellaclasse:

Abbiamoquasiterminato.Torniamoalfile“MainViewController.m”,dobbiamomodi-ficareduecose.Vogliamochechevengapassatoallavistadelleimpostazioniivaloridelpennello,e,viceversa,chevenganoaggiornatidopochel’utentelihavariati.

Iniziatemodificandoilmetodo“flipsideViewControllerDidFinish:”,chetrovategiànellavostra classe come vedete in Codice 10.15 nella pagina successiva.

Page 145: Manuale IOS

145

Comepotetevedere,èstataperprimacosamodificata l’intestazionedelmetodo(proprioquellochevihoaccennatopocofa).Vengono,poi,aggiornatelecaratteristi-chedelpennello,inserendoilnuovocoloreelanuovadimensione.

Ilsecondometododamodificareè“showInfo:”,anch’essogiàdefinitodaXcode:

Codice 10.15: Modifica del metodo “flipsideViewControllerDidFinish:”

1

23

4

5678

- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller nuovoColore:(UIColor*)colore nuovaDimensione:(float)di-mensione{ // aggiorniamo le proprietà del pennello const CGFloat *components = CGColorGetComponents([colore CGCo-lor]); colorePennello = [UIColor colorWithRed:components[0] green:components[1] blue:components[2] alpha:components[3]]; dimensionePennello = dimensione; // chiudiamo la vista delle impostazioni [self dismissModalViewControllerAnimated:YES];}

Codice 10.16: Modifica del metodo “showInfo:”

12

34

5678910

- (IBAction)showInfo:(id)sender { FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:@”FlipsideViewController” bundle:nil]; controller.delegate = self; controller.modalTransitionStyle = UIModalTransitionStyleFlipHo-rizontal; // passiamo i valori attuali del pennello controller.dimensionePennello = dimensionePennello; controller.colorePennello = colorePennello; // visualizziamo la vista delle impostazioni [self presentModalViewController:controller animated:YES];}

Aquestometodoaggiungiamosololerighe6e7,inmododapassareallavistadelleimpostazionileproprietàcorrentidelnostropennello(quellechevengonolettenelmetodo“viewDidLoad”cheabbiamoscrittoprima).

Abbiamoconclusoanchequestaparte!Cliccatesu“Run”etestatecheilvostropan-nellodelleimpostazionifunzionicorrettamente!

c a P I t o l o 1 0M y B r u s h e s

Page 146: Manuale IOS

146

Fig. 10.11: App 11 Beta “MyBrushes”

Page 147: Manuale IOS

147

Parte 3: Inseriamo il salvataggio del disegno

Vogliamooraaggiungereunafunzionemoltoimportante:ilsalvataggiodeldisegnocreato.Permetteremoall’utente,quindi,disalvareilsuodisegno,inmodochepossapoiritrovarlonelrullinofotografico.

Apriamoilfile“MainViewController.xib”,dobbiamoinserireunnuovobottonepercon-sentire all’utente di salvare il proprio disegno. Inseriamolo, come già fatto, nella toolbar:

Fig. 10.12: Inserimento bottone “S

alva”

Creiamoun’azioneperquestobottoneechiamiamola“salvaDisegno”.Eccocomedeveessereilfile“MainViewController.h”:

Codice 10.17: File di interfaccia MainViewController.h

123

4567891011121314151617

#import “FlipsideViewController.h”

@interface MainViewController : UIViewController <FlipsideViewCon-trollerDelegate> { // ultimo punto salvato CGPoint ultimoPunto; // parametri del pennello float dimensionePennello; UIColor *colorePennello;}

@property (strong, nonatomic) IBOutlet UIImageView *viewDisegno;

- (IBAction)cancellaDisegno:(id)sender;- (IBAction)showInfo:(id)sender;- (IBAction)salvaDisegno:(id)sender;

@end

c a P I t o l o 1 0M y B r u s h e s

Page 148: Manuale IOS

148

Dobbiamo ora implementare questometodo “salvaDisegno:”, scrivendo il codicenecessario per salvare l’immagine nella galleria dell’utente. Eccolasuaimplementazione:

Codice 10.18: Codice per salvare l’immagine nella galleria

123

456

789101112131415161718

1920

- (IBAction)salvaDisegno:(id)sender { // salviamo l’immagine nel rullino UIImageWriteToSavedPhotosAlbum(viewDisegno.image, self, @selector(imageSavedToPhotosAlbum: didFinishSavingWithError: contextIn-fo:), nil);}

- (void)imageSavedToPhotosAlbum:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { NSString *messaggio; NSString *titolo; // controlliamo se c’è stato un errore nel messaggio if (!error) { titolo = @”Salvataggio”; messaggio = @”Immagine salvata con successo”; } else { titolo = @”Errore”; messaggio = [error description]; } // visualizziamo un’alert mostrando l’esito del salvataggio UIAlertView *alert = [[UIAlertView alloc] initWithTitle:titolo message:messaggio delegate:nil cancelButtonTitle:@”OK” otherButtonTitles:nil]; [alert show]; }

Comepotetevedereilcodiceèmoltosemplice.Ilmetodosalvautilizzaunmetodochepermettedisalvarel’immaginenelrullinofotografico.Adesso,inoltre,èassocia-toilmetodo“imageSavedToPhotosAlbum:didFinishSavingWithError:contextInfo:”,checontrollal’esitodelsalvataggiodeldisegno.Intalemetodo,infatti,nonvedreteistruzionichesioccupanodelsalvataggio,masolouncontrollose l’operazioneèandataabuonfine.Vieneinfatticontrollatalavariabile“error”(riga10),evieneim-postatounmessaggiodavisualizzarepoiall’utente,chedovràessereavvisatoseil salvataggio si è concluso correttamente oppure se ci sono stati degli errori. Tutto moltosemplicecomesempre!

Abbiamodavveroconcluso!Clicchiamosu“Run”egodiamociilnostropersonalis-simoMyBrushes!

Page 149: Manuale IOS

149

Fig. 10.13a: App 11 “MyBrushes” Fig. 10.13b: App 11 “MyBrushes”

c a P I t o l o 1 0M y B r u s h e s

Page 150: Manuale IOS
Page 151: Manuale IOS

151

c o n c l u s I o n I

Conclusioni

Eora?Dopoaverlettoquestolibrononpotete,ovviamente,considerarvidegliespertiprogrammatori per dispositivi iOS. Avete avuto, comunque, un’ampia panoramica dicosasiaXcode,dicomesisviluppinodellesempliciapplicazioniperiPhone.Percontinuare la vostra avventura in questo mondo dovrete provare, studiare, navigare alla ricerca di nuovi spunti per imparare sempre qualcosa di nuovo. La rete offre davvero tanto sull’argomento, ovviamente il vostro primo riferimento deve sempre essereladocumentazioneufficialediApple.

Vi consiglio, inoltre, di visitare spesso devAPP, la community italiana più grande sullaprogrammazioneperiPhone.Litroverete,oltreame,davverotantepersonedispo-nibili e ben preparate, disposte sempre a darvi una mano. Insomma, tenete devAPP semprecomeprimositodiriferimento;)

Quanto a me, se questo libro vi è piaciuto e lo trovate interessante diffondete la voce, consigliatelo ai vostri amici.

Perqualsiasiinformazione,oppurepersegnalazionisullibroosullaprogrammazio-ne,oanchesoloper fareduechiacchiere,contattatemiutilizzando ilmodulochetrovatesuBubiDevs(http://www.bubidevs.net/contattami).

Allaprossima!

Page 152: Manuale IOS
Page 153: Manuale IOS

153

B I B l I o g r a f I a

Bibliografia

I miei tutorial spesso sono nati prendendo spunto da altre guide trovate su Internet, scrittedaaltrepersone.Miparecorretto,quindi,riportarediseguitoilinkdacuihopresol’ispirazioneperscriverealcunitutorial,chesonocomunquestatiriadattatieriscrittiingranparte.Ilgiustomerito,comunque,spettaancheailegittimiautori.

Capitolo 3:iPhoneDevelopmentCentral,“TrashTutorial”http://www.iphonedevcentral.org/tutorials.php?page=ViewTutorial&id=30&uid=68863015

Capitolo 6:iPhoneNoob,“AccesstheAddressBook”http://iphone.zcentric.com/2008/09/19/access-the-address-book

Capitolo 9:TheAppleBlog,“iPhoneSDKTutorial:BuildaSimpleRSSreaderfortheiPhone”http://theappleblog.com/2008/08/04/tutorial-build-a-simple-rss-reader-for-iphone

Capitolo 10:iPodTouchFansForum,“[Tutorial]Drawingtothescreen”http://www.ipodtouchfans.com/forums/showthread.php?t=132024

Page 154: Manuale IOS

Tutorial pratici per iOS SDK

Scritto da Andrea Busi

Copyright © 2011 - BubiDevsemail:[email protected]

url: www.bubidevs.net

L’autorehacuratolaformascrittael’impaginazionediquestolibro,manonvienedatanessunagaranziaespressaoimplicitadialcuntipoenonsiassumealcunare-sponsabilità per eventuali errori o omissioni. Si declina ogni responsabilità per danni accidentalioconsequenzialiinrelazioneoderivantidall’usodelleinformazioniodeiprogrammi in esso contenute.

Nomiemarchicitatineltestosonogeneralmentedepositatioregistratidallerispet-tive case produttrici.

L’impaginazionegraficaèstatacuratadaMatteoSalvi.

Versione 2.0

Novembre 2011