UNIVERSITA’	
  DEGLI	
  STUDI	
  DI	
  TRIESTE	
  
                                    Facoltà	
  di	
  Ingegneria	
  
             Corso	
  di	
  Laurea	
  specialistica	
  in	
  Ingegneria	
  Informatica	
  
                              Anno	
  Accademico	
  2009/2010	
  
                                                   	
  

         IMPLEMENTAZIONE	
  DI	
  UN	
  APPLICATIVO	
  DI	
  AR	
  
       (Augmented	
  Reality)	
  SU	
  DISPOSITIVO	
  IPHONE	
  PER	
  
         IL	
  RICONOSCIMENTO	
  E	
  LA	
  LOCALIZZAZIONE	
  DI	
  
                        PUNTI	
  D’INTERESSE	
  
                                                                                                           	
  
                                                           Relatore:	
  Prof.ssa	
  Raffaela	
  Cefalo	
  
                                                          Correlatore:	
  Prof.	
  Giorgio	
  Manzoni	
  	
  
	
  
Laureando:	
  Michele	
  Verani	
  
                                                                                                           	
  

                                                                                                           	
  
                                                   	
  
 

                                                                              	
  
       I	
  computer	
  sono	
  incredibilmente	
  veloci,	
  accurati	
  e	
  stupidi.	
  Gli	
  uomini	
  sono	
  incredibilmente	
  lenti,	
  
                  inaccurati	
  e	
  intelligenti.	
  Insieme	
  sono	
  una	
  potenza	
  che	
  supera	
  l'immaginazione.	
  

                                                               	
  –	
  Albert	
  Einstein	
  




	
                                                                                                                                           1-­‐2	
  
 

Sommario	
  

1	
   PREMESSA	
                                                                                                                    1-­5	
  
1.1	
   BREVE	
  DESCRIZIONE	
  DEL	
  LAVORO	
  SVOLTO	
                                                                           1-­5	
  
1.2	
   SUDDIVISIONE	
  DELLO	
  SVILUPPO	
  DELLA	
  TESI	
                                                                        1-­5	
  

2	
   INTRODUZIONE	
                                                                                                                2-­5	
  
2.1	
   SISTEMA	
  OPERATIVO	
  IPHONE	
  OS	
                                                                                     2-­5	
  
2.1.1	
   STRUTTURA	
  DEL	
  SISTEMA	
  OPERATIVO	
  IPHONE	
  OS	
                                                               2-­‐6	
  
2.2	
   STRUMENTI	
  DI	
  SVILUPPO	
  DISPONIBILI	
  PER	
  L’IPHONE	
                                                           2-­10	
  
2.2.1	
   IL	
  FRAME	
  WORK	
  COCOA	
                                                                                          2-­‐10	
  
2.2.2	
   LA	
  PIATTAFORMA	
  SDK	
                                                                                              2-­‐11	
  
2.2.3	
   XCODE	
                                                                                                                 2-­‐11	
  
2.2.4	
   INTERFACE	
  BUILDER	
                                                                                                  2-­‐12	
  
2.2.5	
   IPHONE	
  OS	
  SIMULATOR	
                                                                                             2-­‐14	
  
2.3	
   OBJECTIVE-­C	
                                                                                                            2-­14	
  
2.3.1	
   OGGETTI,	
  CLASSI,	
  METODI	
  E	
  ISTANZE	
                                                                         2-­‐14	
  
2.3.2	
   INTERFACCE	
  E	
  IMPLEMENTAZIONI	
                                                                                    2-­‐14	
  
2.3.3	
   MESSAGGI	
  E	
  POLIMORFISMO	
                                                                                         2-­‐16	
  
2.3.4	
   OBJECTIVE-­‐C	
  E	
  OGGETTI	
  COCOA	
                                                                                2-­‐16	
  
2.3.5	
   DINAMICITÀ	
  DELL’OBJECTIVE-­‐C	
                                                                                      2-­‐16	
  
2.3.6	
   LE	
  CLASSI	
  ROOT	
                                                                                                  2-­‐17	
  
2.3.7	
   ALLOCAZIONE	
  E	
  RILASCIO	
  DEGLI	
  OGGETTI	
                                                                      2-­‐18	
  
2.3.8	
   INTROSPECTION	
                                                                                                         2-­‐21	
  
2.3.9	
   OGGETTI	
  MODIFICABILI	
                                                                                               2-­‐21	
  
2.3.10	
   RAGGRUPPAMENTI	
  DI	
  CLASSI	
                                                                                       2-­‐22	
  

3	
   PROGETTAZIONE	
                                                                                                             3-­22	
  
3.1	
   DEFINIZIONE	
  DELL’OBIETTIVO	
                                                                                           3-­23	
  
3.2	
   ANALISI	
  DEI	
  PROBLEMI	
  GENERICI	
                                                                                  3-­23	
  
3.3	
   SCOMPOSIZIONE	
  DELLE	
  SINGOLE	
  PROBLEMATICHE	
                                                                      3-­23	
  
3.3.1	
   GESTIONE	
  DEL	
  FRAME	
  WORK	
  CORELOCATION	
                                                                      3-­‐24	
  
3.3.2	
   GESTIONE	
  DELL’UIACCELEROMETER	
                                                                                      3-­‐27	
  
3.3.3	
   GESTIONE	
  DELLA	
  FOTOCAMERA	
                                                                                       3-­‐28	
  
3.3.4	
   LA	
  MEMORIZZAZIONE	
  DEI	
  DATI	
                                                                                   3-­‐29	
  
3.3.5	
   USO	
  DEI	
  DATI	
  PROVENIENTI	
  DA	
  UN	
  WEB	
  SERVICE	
                                                       3-­‐32	
  
3.3.6	
   IL	
  FRAME	
  WORK	
  MAPKIT	
                                                                                         3-­‐35	
  
3.3.7	
   LA	
  LIBRERIA	
  DELL’”AUGMENTED	
  REALITY”(ARKIT)	
                                                                  3-­‐38	
  

4	
   REALIZZAZIONE	
                                                                                                             4-­39	
  
4.1	
   SPECIFICHE	
                                                                                                            4-­40	
  
4.1.1	
   MEMORIZZAZIONE	
  PERSISTENTE	
  DEI	
  PUNTI	
  D’INTERESSE	
  E	
  INTEGRAZIONE	
  NEL	
  PROGRAMMA	
  DELL’USO	
  DELLA	
  
FOTOCAMERA	
                                                                                                                    4-­‐40	
  
4.1.2	
   IMPLEMENTAZIONE	
  DELL’AUGMENTED	
  REALITY	
  (ARKIT)	
                                                             4-­‐71	
  
4.1.3	
   L’UTILIZZO	
  DEI	
  WEB	
  SERVICES	
  NELL’APPLICAZIONE	
                                                           4-­‐75	
  
4.1.4	
   DEFINIZIONE	
  DELLE	
  FUNZIONI	
  TIPICHE	
  DEI	
  SOFTWARE	
  DI	
  NAVIGAZIONE	
                                 4-­‐88	
  
4.2	
   LO	
  SVILUPPO	
  DEL	
  PROGRAMMA	
  COMPLETO	
                                                                   4-­101	
  

       	
                                                                                                                           1-­‐3	
  
5	
   COLLAUDO	
                                                                                           5-­105	
  
5.1	
         COLLAUDO	
  SULL’IPHONE	
  SIMULATOR	
                                                       5-­106	
  
5.2	
         VISUALIZZAZIONE	
  DEI	
  PUNTI	
  D’INTERESSE	
                                             5-­106	
  
5.3	
         INSERIMENTO	
  MANUALE	
  DEI	
  PUNTI	
  D’INTERESSE	
  DELL’UTENTE	
                       5-­107	
  
5.4	
         DISTRIBUZIONE	
  E	
  VISUALIZZAZIONE	
  DEI	
  PUNTI	
  D’INTERESSE	
  SULLA	
  MAPPA	
     5-­108	
  
5.5	
         COLLAUDO	
  DELL’”AUGMENTED	
  REALITY”	
                                                    5-­108	
  
5.6	
         TEST	
  DELLE	
  FUNZIONALITÀ	
  DI	
  NAVIGAZIONE	
                                         5-­109	
  

6	
   CONCLUSIONI	
                                                                                        6-­110	
  
6.1	
   PREGI	
  E	
  DIFETTI	
  INDIVIDUATI	
  NEL	
  PROGRAMMA	
                                         6-­111	
  
6.1.1	
   PREGI	
                                                                                          6-­‐111	
  
6.1.2	
   DIFETTI	
                                                                                        6-­‐111	
  
6.1.3	
   SVILUPPI	
  FUTURI	
                                                                             6-­‐111	
  

7	
   BIBLIOGRAFIA	
                                                                                       7-­113	
  

8	
   RINGRAZIAMENTI	
                                                                                     8-­113	
  
	
  




       	
                                                                                                      1-­‐4	
  
1 PREMESSA	
  
      	
  

1.1 Breve	
  descrizione	
  del	
  lavoro	
  svolto	
  
L’obiettivo	
  di	
  questo	
  progetto	
  è	
  lo	
  sviluppo	
  di	
  un	
  programma	
  per	
  Iphone	
  che	
  coniuga	
  le	
  funzionalità	
  
fornite	
  dalla	
  libreria	
  dell’“Augmented	
  Reality”(ARKit	
  for	
  Iphone)	
  con	
  le	
  caratteristiche	
  disponibili	
  in	
  
un	
  generico	
  software	
  di	
  navigazione,	
  quali	
  la	
  geo	
  localizzazione	
  dell’utente	
  e	
  l’individuazione	
  sulla	
  
mappa	
  dei	
  punti	
  d’interesse	
  disponibili	
  nella	
  memoria	
  del	
  telefono	
  e	
  quelli	
  scaricati	
  dalla	
  rete,	
  
fornendo	
  inoltre	
  la	
  possibilità	
  di	
  inserire	
  delle	
  informazioni	
  aggiuntive	
  nella	
  descrizione	
  di	
  ogni	
  punto,	
  
sia	
  di	
  tipo	
  visivo,	
  come	
  le	
  foto,	
  che	
  di	
  tipo	
  testuale.	
  

Per	
  descrivere	
  in	
  maniera	
  esaustiva	
  questo	
  progetto,	
  la	
  trattazione	
  è	
  stata	
  divisa	
  in	
  più	
  capitoli	
  nei	
  
quali	
  sono	
  state	
  affrontate	
  le	
  singole	
  problematiche	
  e	
  soluzioni	
  adottate	
  in	
  corso	
  d'opera	
  durante	
  
l'elaborazione	
  del	
  lavoro	
  finale.	
  

1.2 Suddivisione	
  dello	
  sviluppo	
  della	
  tesi	
  
Il	
  lavoro	
  di	
  tesi	
  è	
  stato	
  suddiviso	
  in	
  sei	
  capitoli,	
  ciascuno	
  dei	
  quali	
  tratta	
  in	
  maniera	
  specifica	
  le	
  fasi	
  di	
  
lavoro	
  svolte	
  durante	
  lo	
  sviluppo	
  della	
  tesi:	
  
	
  
           1. Premessa	
  
           2. Introduzione	
  
           3. Progettazione	
  
           4. Realizzazione	
  
           5. Collaudo	
  
           6. Conclusioni	
  
	
  
Nell’introduzione	
  è	
  stata	
  fatta	
  una	
  descrizione	
  della	
  struttura	
  hardware	
  e	
  logica	
  dell’Iphone	
  usato	
  per	
  
lo	
   sviluppo	
   della	
   tesi,	
   andando	
   a	
   descrivere	
   le	
   librerie	
   e	
   i	
   frameworks	
   implementati	
   al	
   suo	
   interno,	
  
passando	
   poi	
   alla	
   descrizione	
   del	
   tool	
   di	
   sviluppo	
   adottato	
   e	
   a	
   un’analisi	
   del	
   linguaggio	
   usato	
   per	
   la	
  
realizzazione	
  del	
  programma	
  richiesto.	
  
Nella	
  progettazione	
  si	
  sono	
  trattate	
  le	
  problematiche	
  riguardanti	
  lo	
  sviluppo	
  del	
  programma,	
  partendo	
  
dall’analisi	
   dell’utilizzo	
   dei	
   frame	
   work	
   CoreLocation	
   e	
   Mapkit,	
   passando	
   poi	
   ai	
   problemi	
   della	
  
memorizzazione	
  dei	
  punti	
  d’interesse	
  e	
  l’iterazione	
  del	
  sistema	
  con	
  i	
  web	
  services,	
  finendo	
  poi	
  con	
  una	
  
descrizione	
  dettagliata	
  della	
  gestione	
  delle	
  librerie	
  dell’”Augmented	
  Reality”.	
  
Si	
   è	
   passati	
   poi	
   alla	
   descrizione	
   della	
   fase	
   operativa,	
   ossia	
   la	
   parte	
   della	
   realizzazione	
   dei	
   moduli	
  
necessari	
   al	
   funzionamento	
   del	
   programma,	
   tenendo	
   conto	
   delle	
   specifiche	
   iniziali	
   del	
   progetto	
   ed	
  
esponendo	
  in	
  maniera	
  completa	
  l’implementazione	
  dell’applicativo.	
  
Nel	
   penultimo	
   capitolo	
   è	
   stato	
   trattato	
   il	
   collaudo	
   del	
   programma	
   sul	
   simulatore,	
  con	
   l’effettuazione	
   di	
  
un’analisi	
   del	
   funzionamento	
   dettagliato	
   delle	
   varie	
   parti	
   dell’applicativo	
   e	
   con	
   una	
   prova	
   complessiva	
  
del	
  programma	
  richiesto.	
  	
  
Nell’ultimo	
  capitolo	
  si	
  è	
  cercato	
  invece	
  di	
  analizzare	
  in	
  maniera	
  obiettiva	
  il	
  progetto,	
  trovando	
  i	
  suoi	
  
eventuali	
  pregi	
  e	
  difetti	
  ed	
  esplicando	
  in	
  maniera	
  sintetica	
  gli	
  sviluppi	
  futuri	
  ipotizzati	
  per	
  migliorarlo.	
  


2 INTRODUZIONE	
  
      	
  

2.1 Sistema	
  operativo	
  Iphone	
  OS	
  
Negli	
   ultimi	
   decenni	
   i	
   dispositivi	
   mobili	
   hanno	
   conquistato	
   fette	
   di	
   mercato	
   sempre	
   più	
   rilevanti	
  
andando	
  di	
  pari	
  passo	
  con	
  l'incremento	
  delle	
  funzionalità	
  avvenuto	
  tra	
  i	
  primi	
  e	
  gli	
  ultimi	
  modelli	
  nati.	
  
Con	
   lo	
   sviluppo	
   di	
   hardware	
   sempre	
   più	
   sofisticati	
   è	
   stato	
   possibile	
   quindi	
   fornire	
   tali	
   dispositivi	
   di	
  
caratteristiche	
   anche	
   complesse,	
   come	
   il	
   riconoscimento	
   da	
   parte	
   del	
   sistema	
   di	
   file	
   musicali,	
   di	
  

      	
                                                                                                                                                            2-­‐5	
  
riproduzione	
  di	
  video,	
  del	
  collegamento	
  ad	
  internet	
  tramite	
  rete	
  Wi-­‐Fi	
  e	
  dell'acquisizione,	
  tramite	
  un	
  
ricevitore	
  interno,	
  del	
  segnale	
  GPS,	
  consentendo	
  la	
  geo-­‐localizzazione	
  dell'utente.	
  	
  
Essendo	
   prodotti	
   così	
   versatili,	
   è	
   intuibile	
   quanto	
   siano	
   diventati	
   presenti	
   nelle	
   abitudini	
   dei	
  
consumatori	
   e	
   abbiano	
   di	
   conseguenza	
   indirizzato	
   i	
   produttori	
   stessi	
   ad	
   attuare	
   e	
   sviluppare	
  
innovative	
   scelte	
   commerciali.	
   Di	
   conseguenza,	
   quindi,	
   con	
   il	
   crescere	
   delle	
   prestazioni	
   hardware,	
  
infatti,	
   sono	
   cresciuti	
   anche	
   gli	
   investimenti	
   nella	
   progettazione	
   di	
   software	
   che	
   li	
   sfrutta,	
   ma	
  
nonostante	
  ciò,	
  i	
  sistemi	
  operativi	
  nati	
  per	
  girare	
  in	
  questi	
  ambienti,	
  devono	
  comunque	
  far	
  fronte	
  alle	
  
carenze	
   hardware	
   che	
   tali	
   dispositivi	
   hanno	
   rispetto	
   alle	
   macchine	
   tradizionali,	
   oltre	
   a	
   dover	
   gestire	
  
interfacce	
  utente	
  notevolmente	
  semplificate,	
  considerando	
  gli	
  schermi	
  di	
  ridotte	
  dimensioni.	
  	
  
	
  
L'iPhone	
   è	
   un	
   prodotto	
   orientato	
   al	
   mercato	
   consumer	
   non	
   avendo	
   quindi	
   un	
   target	
   di	
   tipo	
   business;	
   i	
  
suoi	
   punti	
   di	
   forza	
   sono	
   la	
   facilità	
   d'uso,	
   l'estetica	
   e	
   l'usabilità	
   nella	
   navigazione	
   in	
   internet,	
   oltre	
  ad	
  
avere	
  una	
  suite	
  completa	
  di	
  programmi	
  per	
  l'ufficio.	
  
L'innovazione	
  che	
  ha	
  portato	
  nel	
  settore	
  è	
  sicuramente	
  dovuta	
  alle	
  sue	
  caratteristiche	
  hardware,	
  ma	
  
anche	
   alla	
   sua	
   usabilità,	
   superiore	
   a	
   tutti	
   i	
   suoi	
   predecessori.	
   In	
   definitiva	
   è	
   la	
   sintesi	
   di	
   un	
   dispositivo	
  
di	
  elevato	
  design,	
  supportato	
  da	
  un	
  sistema	
  operativo	
  semplificato	
  che	
  deriva	
  dal	
  Mac	
  OS	
  X,	
  il	
  sistema	
  
Apple	
   per	
   computer	
   Desktop,	
   ricalcando	
   abbastanza	
   fedelmente	
   la	
   struttura	
   che	
   si	
   trova	
   sugli	
   Apple	
  
ma	
   comunque	
   differenziandosi	
   da	
   questi	
   per	
   l’implementazione	
   di	
   un'interfaccia	
   grafica	
   molto	
  
semplificata.	
  
	
  

2.1.1 Struttura	
  del	
  sistema	
  operativo	
  Iphone	
  OS	
  
Apple	
  inc.	
  ha	
  fatto	
  il	
  suo	
  ingresso	
  nei	
  dispositivi	
  mobili	
  nel	
  2007	
  con	
  una	
  prima	
  versione	
  dell'iPhone,	
  
successivamente	
   nel	
   luglio	
   del	
   2008	
   è	
   stato	
   presentato	
   un	
   secondo	
   modello	
   disponibile	
   in	
   molti	
   più	
  
Paesi.	
  
Come	
  tutti	
  gli	
  altri	
  prodotti	
  Apple,	
  anche	
  con	
  l'iPhone,	
  la	
  casa	
  produttrice	
  ha	
  deciso	
  di	
  legare	
  il	
  sistema	
  
operativo	
   ad	
   un	
   unico	
   dispositivo	
   hardware,	
   a	
   differenza	
   quindi	
   dei	
   suoi	
   concorrenti,	
   i	
   quali	
   invece	
  
sono/possono	
   essere	
   installati	
   su	
   dispositivi	
   diversi,	
   sia	
   in	
   architettura	
   che	
   nel	
   produttore.(vedi	
   il	
  
sistema	
  operativo	
  Android	
  e	
  Windows	
  Mobile).	
  
L'iPhone	
   OS	
   invece,	
   non	
   ha	
   previsto	
   la	
   portabilità	
   della	
   sua	
   logica	
   su	
   altri	
   telefoni	
   ed	
   è	
   direttamente	
  
derivato	
  dal	
  sistema	
  operativo	
  già	
  utilizzato	
  in	
  ambiente	
  desktop.	
  
	
  

2.1.1.1 Descrizione	
  della	
  logica	
  dell’Iphone	
  OS	
  
	
  




	
  

Figura	
  1:	
  struttura	
  logica	
  del	
  sistema	
  operativo	
  

Come	
  si	
  vede	
  dalla	
  figura	
  1,	
  	
  il	
  sistema	
  Iphone	
  OS	
  è	
  organizzato	
  per	
  strati,	
  ognuno	
  dei	
  quali	
  dipendente	
  
da	
  quello	
  sottostante	
  ma	
  che	
  gestisce	
  servizi	
  e	
  periferiche	
  	
  diverse.	
  

       	
                                                                                                                                                                    2-­‐6	
  
Il	
  sistema,	
  sotto	
  lo	
  strato	
  dell’applicazione	
  (application	
  layer)	
  è	
  strutturato	
  nella	
  seguente	
  maniera:	
  

       •      Application	
  Frameworks	
  in	
  cui	
  è	
  contenuto	
  l’UIKit	
  
       •      Lo	
  strato	
  riguardante	
  la	
  gestione	
  dell’audio	
  e	
  della	
  grafica	
  
       •      Core	
  Frameworks	
  in	
  cui	
  è	
  contenuto	
  il	
  Foundation	
  
       •      Lo	
  strato	
  Core	
  OS	
  (ovvero	
  il	
  Kernel	
  del	
  sistema)	
  	
  

	
  

2.1.1.1.1 Application	
  Frameworks	
  
E’	
  lo	
  strato	
  che	
  racchiude	
  uno	
  dei	
  frame	
  work	
  più	
  utilizzati	
  nella	
  programmazione	
  in	
  Objective-­‐C:	
  	
  

       ⇒ UIKit	
  

Esso	
   è	
   uno	
   dei	
   più	
   usati	
   perché	
   fornisce	
   gli	
   oggetti	
   che	
   le	
   applicazioni	
   mostrano	
   nell'interfaccia	
   utente	
  
e	
  definisce	
  la	
  struttura	
  per	
  il	
  comportamento	
  della	
  nostra	
  applicazione,	
  inclusa	
  la	
  gestione	
  degli	
  eventi,	
  
curando	
  anche	
  la	
  gestione	
  dei	
  sensori	
  implementati	
  all'interno	
  del	
  telefono	
  stesso,	
  quali	
  ad	
  esempio	
  il	
  
ricevitore	
  GPS,	
  il	
  magnetometro	
  (presente	
  nella	
  versione	
  3GS)	
  e	
  l'accelerometro.	
  
	
  
L’interfaccia	
  grafica	
  dell’applicazione,	
  quindi	
  può	
  essere	
  sviluppata	
  in	
  tre	
  modi	
  differenti:	
  

              1) Sfruttando	
  l’Object	
  Library	
  posto	
  nell’Interface	
  Builder;	
  
              2) Costruendo	
  gli	
  oggetti	
  attraverso	
  la	
  disposizione	
  e	
  la	
  programmazione	
  in	
  un	
  frame	
  work;	
  

              3) Implementando	
   gli	
   oggetti	
   delle	
   interfacce	
   utente	
   attraverso	
   sottoclassi	
   della	
   classe	
   madre	
  
                 UIView.	
  
	
  

Una	
  delle	
  caratteristiche,	
  che	
  differenziano	
  questi	
  oggetti	
  grafici	
  con	
  quelli	
  implementati	
  nel	
  MAC	
  OS	
  X	
  
sono	
  le	
  dimensioni	
  dei	
  singoli	
  componenti:	
  necessitano	
  di	
  essere	
  adeguate	
  allo	
  schermo	
  dell’Iphone	
  ed	
  
all’uso	
  delle	
  dita	
  da	
  parte	
  dell’utente	
  sul	
  display	
  del	
  telefono.	
  

In	
  UIKit,	
  le	
  classi	
  degli	
  oggetti	
  grafici	
  possono	
  essere	
  divise	
  nei	
  seguenti	
  gruppi:	
  

       1)     Controlli	
  
       2)     Modal	
  views	
  
       3)     Scroll	
  views	
  (implementazione	
  delle	
  view	
  di	
  tabelle,	
  testo	
  e	
  web)	
  
       4)     Toolbar,	
  navigation	
  bar	
  e	
  view	
  controller	
  
	
  

Per	
   quanto	
   riguarda	
   il	
   primo	
   tipo,	
   gli	
   oggetti	
   che	
   ne	
   fanno	
   parte	
   sono	
   quelli	
   derivanti	
   dalle	
   classi	
  
UIControl	
  che	
  comprendono	
  gli	
  UIButton	
  (pulsanti),	
  gli	
  UISwitch(quelli	
  che	
  simulano	
  lo	
  switch	
  on/off),	
  
e	
  quelli	
  che	
  riguardano	
  la	
  selezione	
  di	
  gruppi	
  multidimensionali	
  (UIPickerView)	
  e	
  l'UIPageControl.	
  
Per	
  il	
  gruppo	
  modal	
  view,	
  appartengono	
  le	
  classi	
  UIActionSheet	
  ed	
  UIAlertView,	
  ereditate	
  ambedue	
  da	
  
UIModalView.	
   La	
   prima	
   visualizzerà	
   i	
   messaggi	
   all'utente	
   sotto	
   forma	
   di	
   fogli	
   allegati	
   oppure	
   viste	
  
speciali,	
  mentre	
  la	
  seconda	
  sotto	
  forma	
  di	
  messaggi	
  di	
  tipo	
  “alert”.	
  	
  
Apparterrà	
  all’ultimo	
  gruppo,	
  la	
  classe	
  dell’UIViewController,	
  che	
  fornisce	
  metodi	
  gestire	
  in	
  generale	
  le	
  
“view”,	
   i	
   messaggi	
   di	
   warning	
   della	
   gestione	
   della	
   memoria	
   dell'applicazione	
   oppure	
   proprio	
   per	
  
coordinare	
  le	
  toolbar	
  e	
  le	
  navigation	
  bar.	
  
	
  

2.1.1.1.2 Graphics	
  e	
  Audio	
  
       ⇒ Graphics	
  

E'	
   uno	
   degli	
   elementi	
   più	
   importanti	
   nello	
   sviluppo	
   di	
   un'applicazione,	
   perché	
   consente	
   all'utente	
   di	
  
interagire	
  con	
  il	
  sistema,	
  permettendo	
  al	
  programmatore	
  di	
  sfruttare	
  immagini,	
  view	
  e	
  funzioni	
  fornite	
  
dal	
  framework	
  UIKit	
  proprio	
  per	
  migliorare	
  l'interfaccia	
  utente	
  dell'applicazione	
  sviluppata.	
  	
  

       	
                                                                                                                                                         2-­‐7	
  
Inoltre,	
   grazie	
   a	
   questa	
   gestione,	
   ha	
   la	
   possibilità	
   di	
   creare	
   degli	
   elementi	
   personalizzabili	
   con	
   dei	
  
framework	
  supplementari	
  resi	
  accessibili	
  dal	
  tool	
  di	
  sviluppo:	
  
	
  
     1. QuartzCore.framework	
  
     2. OpenGLES.framework	
  
     3. CoreGraphics.framework	
  
	
  

       1. Il	
   QuartzCore	
   frame	
   work	
   fornisce	
   lo	
   sviluppatore	
   di	
   un'interfaccia	
   di	
   alto	
   livello	
   per	
   la	
  
            creazione	
   di	
   animazioni	
   personalizzate	
   che	
   sono	
   concepite	
   attraverso	
   l’adozione	
   delle	
  
            interfacce	
  di	
  CoreAnimation.	
  	
  
       2. Il	
   frame	
   work	
   OpenGL	
   ES	
   si	
   basa	
   sulle	
   specifiche	
   OpenGL	
   ES	
   v1.1	
   e	
   fornisce	
   strumenti	
   per	
   il	
  
            disegno	
   di	
   contenuti	
   2D	
   e	
   3D.	
   È	
   un	
   frame	
   work	
   scritto	
   in	
   C	
   che	
   lavora	
   a	
   stretto	
   contatto	
   con	
  
            l'hardware	
  per	
  fornire	
  un	
  elevato	
  frame	
  rate,	
  fondamentale	
  nello	
  sviluppo	
  di	
  giochi.	
  
       3. Si	
  tratta	
  dello	
  stesso	
  frame	
  work	
  utilizzato	
  per	
  il	
  disegno	
  in	
  Mac	
  OS	
  X,	
  anche	
  se	
  in	
  questo	
  caso	
  è	
  
            usato	
   nell'Iphone	
   OS.	
   Anche	
   in	
   quest’ambiente,	
   comunque	
   è	
   implementato	
   per	
   la	
  
            rappresentazione	
  di	
  oggetti	
  grafici,	
  semplificando	
  il	
  riutilizzo	
  dei	
  contenuti	
  dell’interfaccia.	
  
       	
  
       ⇒ Audio	
  
	
  
Per	
  quanto	
  riguarda	
  questo	
  sotto	
  strato,	
  possiamo	
  distinguere	
  i	
  seguenti	
  tipi	
  di	
  frame	
  work:	
  
	
  

       1.     CoreAudio.framework	
  
       2.     AudioToolbox.framework	
  
       3.     AudioUnit.framework	
  
       4.     OpenAL	
  
	
  
       1. CoreAudio.framework	
   fornisce	
   informazioni	
   sulle	
   caratteristiche	
   e	
   sul	
   formato	
   audio	
   del	
   file,	
  
          fornendo	
  servizi	
  di	
  riproduzione	
  e	
  registrazione	
  per	
  file	
  e	
  flussi	
  audio.	
  	
  
       2. Audio	
   Toolbox	
   fornisce	
   servizi	
   di	
   riproduzione	
   e	
   registrazione	
   per	
   file	
   e	
   flussi	
   audio.	
   Questo	
  
          frame	
  work	
  prevede	
  anche	
  il	
  supporto	
  per	
  la	
  gestione	
  di	
  file	
  audio	
  e	
  riproduzione	
  di	
  suoni	
  e	
  
          allarmi	
  di	
  sistema.	
  
       3. AudioUnit	
  fornisce	
  servizi	
  per	
  l'utilizzo	
  di	
  unità	
  audio	
  e	
  moduli	
  di	
  elaborazione.	
  
       4. Il	
   sistema	
   operativo	
   dell’Iphone	
   include	
   inoltre	
   anche	
   il	
   supporto	
   per	
   l’audio	
   Open	
   Library	
  
          (OpenAL)	
   che	
   è	
   uno	
   standard,	
   multi	
   piattaforma	
   per	
   la	
   gestione	
   3D	
   dell’audio	
   nelle	
  
          applicazioni.	
  

	
  

2.1.1.1.3 Core	
  frameworks	
  
Questo	
  livello	
  include	
  il	
  frame	
  work	
  Foundation	
  e	
  fornisce	
  i	
  servizi	
  (chiamato	
  anche	
  Core	
  Services)	
  
necessari	
  a	
  tutte	
  le	
  applicazioni,	
  dall'accesso	
  dei	
  dati	
  dei	
  contatti(Address	
  book)	
  al	
  parsing	
  degli	
  
elementi	
  XML(con	
  l'utilizzo	
  dell'NSXMLParser).	
  
	
  
     ⇒ Foundation	
  

	
  
Questo	
  frame	
  work	
  in	
  pratica	
  definisce	
  un	
  insieme	
  di	
  classi	
  che	
  possono	
  essere	
  usate	
  per	
  ogni	
  tipo	
  di	
  
software	
   Cocoa,	
   fornendo	
   i	
   comportamenti	
   base	
   degli	
   oggetti,	
   i	
   meccanismi	
   per	
   la	
   loro	
   gestione	
   e	
  
definendo	
   gli	
   oggetti	
   per	
   i	
   tipi	
   di	
   dati	
   primitivi,	
   collezioni	
   e	
   servizi	
   del	
   sistema	
   operativo:	
   potrebbe	
  
essere	
  considerato	
  come	
  un	
  wrapper	
  ad	
  oggetti	
  del	
  frame	
  work	
  Core	
  Foundation.	
  
Un	
   oggetto	
   per	
   potersi	
   definire	
   appartenente	
   a	
   Foundation	
   deve	
   derivare	
   dalla	
   “classe	
   madre”	
  
NSObject	
   e	
   soprattutto	
   non	
   deve	
   essere	
   coinvolto	
   o	
   usato	
   esclusivamente	
   nell’interfaccia	
   utente	
   del	
  
programma.	
  
       	
                                                                                                                                                                   2-­‐8	
  
Gli	
  scopi	
  per	
  cui	
  è	
  stato	
  pensato,	
  sono	
  molteplici,	
  tra	
  i	
  quali	
  spiccano	
  i	
  seguenti:	
  
	
  
        ⇒ Il	
  supporto	
  all'internazionalizzazione	
  e	
  alla	
  localizzazione	
  attraverso	
  le	
  stringhe	
  Unicode	
  
        ⇒ Il	
  supporto	
  alla	
  persistenza	
  di	
  dati	
  e	
  a	
  oggetti	
  distribuiti	
  
        ⇒ La	
  fornitura	
  di	
  misure	
  d’indipendenza	
  dal	
  sistema	
  operativo	
  orientato	
  alla	
  portabilità	
  
        ⇒ L’offerta	
   di	
   oggetti	
   wrapper	
   per	
   la	
   programmazione	
   e	
   definizione	
   di	
   primitive,	
   come	
   valori	
  
            numerici,	
   stringhe,	
   collection,	
   includendo	
   classi	
   per	
   l'accesso	
   ai	
   servizi	
   del	
   sistema,	
   quali	
   ad	
  
            esempio	
  porte,	
  thread	
  e	
  file	
  system	
  
	
  
        ⇒ Servizi	
  offerti	
  
	
  
I	
  servizi	
  offerti	
  da	
  questo	
  strato	
  sono	
  elencati	
  qui	
  di	
  seguito:	
  
	
  

       1.      Address	
  Book	
  
       2.      Core	
  Foundation	
  
       3.      Core	
  Location	
  
       4.      CFNetwork	
  
       5.      Security	
  
       6.      SQLite	
  &	
  Core	
  Data	
  
       7.      XML	
  	
  
	
  

          1. Address	
   Book	
   consente	
   un	
   accesso	
   diretto	
   ai	
   dati	
   riguardanti	
   i	
   contatti	
   contenuti	
   nell'agenda	
  
             telefonica,	
  fornendo	
  una	
  completa	
  interfaccia	
  grafica	
  per	
  la	
  rappresentazione	
  dei	
  dati	
  richiesti,	
  
             attraverso	
  l'utilizzo	
  di	
  determinate	
  classi	
  dell’Objective-­‐C	
  
          2. Core	
   Foundation	
   è	
   un	
   insieme	
   d’interfacce	
   che	
   forniscono	
   la	
   gestione	
   dei	
   dati	
   di	
   base	
   e	
   dei	
  
             servizi	
  per	
  le	
  applicazioni	
  su	
  iPhone,	
  consentendo:	
  
                a) La	
  gestione	
  :	
  
                          ⇒ Di	
  stringhe	
  
                          ⇒ Delle	
  date	
  e	
  del	
  tempo	
  
                          ⇒ Delle	
  preferenze	
  
                          ⇒ Di	
  blocchi	
  di	
  dati	
  non	
  elaborati	
  
	
  

                    b) Il	
  supporto	
  per:	
  
                       	
  
                               ⇒ Tipi	
  di	
  dato	
  Collection	
  
                               ⇒ La	
  manipolazione	
  di	
  stream	
  e	
  di	
  URL	
  
                               ⇒ La	
  comunicazione	
  di	
  porte	
  e	
  processi	
  

          3. Core	
   Location	
   consente	
   di	
   stabilire	
   la	
   corretta	
   posizione	
   di	
   latitudine	
   e	
   longitudine	
   in	
   un	
  
             determinato	
   istante	
   dell'utente,	
   sfruttando	
   secondo	
   i	
   casi,	
   il	
   ricevitore	
   GPS,	
   la	
   triangolazione	
  
             delle	
  celle	
  o	
  le	
  informazioni	
  del	
  segnale	
  wi-­‐fi,	
  con	
  una	
  precisione	
  della	
  posizione	
  che	
  cambia	
  
             secondo	
  la	
  metodologia	
  utilizzata.	
  
          4. CFNetwork	
   è	
   un	
   set	
   di	
   interfacce	
   che	
   fornisce	
   astrazioni	
   orientate	
   ad	
   oggetti	
   per	
   gestire	
   i	
  
             protocolli	
   di	
   networking	
   che	
   aiutano	
   nel	
   controllo	
   dettagliato	
   sul	
   protocollo	
   dello	
   stack	
   e	
  
             facilitano	
   l'utilizzo	
   di	
   costrutti	
   di	
   basso	
   livello	
   come	
   i	
   socket	
   BSD,	
   con	
   lo	
   scopo	
   di	
   facilitare	
   i	
  
             compiti	
  di	
  comunicazione	
  via	
  FTP,	
  server	
  HTTP	
  e	
  la	
  risoluzione	
  di	
  host	
  DNS.	
  
          5. 	
  Security	
   è	
   un	
   frame	
   work	
   che	
   offre	
   un’integrazione	
   alle	
   caratteristiche	
   già	
   esistenti	
   sulla	
  
             sicurezza	
   esplicitamente	
   dedicato	
   agli	
   sviluppatori	
   che	
   vogliano	
   aumentare	
   la	
   security	
   nella	
  
             gestione	
  dei	
  dati	
  nelle	
  applicazioni.	
  	
  
             Tale	
   frame	
   work	
   fornisce	
   interfacce	
   per	
   gestire	
   certificati	
   a	
   chiave	
   pubblica	
   e	
   privata	
   e	
  
             politiche	
   di	
   sicurezza,	
   supportando	
   la	
   generazione	
   pseudo	
   casuale	
   di	
   numeri	
  

       	
                                                                                                                                                                   2-­‐9	
  
crittograficamente	
   sicuri	
   e	
   abilitando	
   il	
   salvataggio	
   di	
   certificati	
   e	
   chiavi	
   crittografate	
   nel	
  
             portachiavi	
  (keychen),	
  un	
  luogo	
  sicuro	
  per	
  salvare	
  dati	
  sensibili	
  degli	
  utenti.	
  
          6. SQLite	
   è	
   una	
   libreria	
   che	
   dà	
   la	
   possibilità	
   di	
   integrare	
   nell'applicazione	
   un	
   piccolo	
   database	
  
             SQL,	
   senza	
   dover	
   accedere	
   in	
   remoto	
   a	
   un’altra	
   base	
   di	
   dati,	
   consentendo	
   un	
   accesso	
   più	
  
             rapido	
  ai	
  record	
  delle	
  tabelle.	
  
          7. Core	
  Data	
  è	
  una	
  libreria	
  aggiunta	
  con	
  l'ultima	
  release	
  del	
  sistema	
  operativo	
  Iphone	
  OS	
  3.0	
  SDK.	
  
             Rispetto	
   alla	
   precedente,	
   offre	
   dei	
   vantaggi	
   in	
   termini	
   di	
   prestazioni	
   sulla	
   memorizzazione	
   dei	
  
             dati	
  in	
  tabelle.	
  
             Si	
  articola	
  in	
  tre	
  elementi:	
  
                    ⇒ managed	
  object	
  models	
  
                    ⇒ managed	
  object	
  contexts	
  
                    ⇒ persistent	
  data	
  store	
  
	
  

                      a. Un	
   “managed	
   object	
   model”	
   contiene	
   un	
   grafo	
   di	
   oggetti,	
   altresì	
   definito	
   come	
   una	
  
                         “collezione”	
  di	
  oggetti	
  e	
  relazioni	
  uno	
  a	
  molti	
  
                      b. 	
  Il	
   “managed	
   object	
   context”	
   è	
   creato	
   con	
   lo	
   scopo	
   di	
   contenere	
   gli	
   oggetti	
   creati	
   da	
  
                         entità	
  nel	
  “managed	
  object	
  model”	
  ed	
  è	
  costituito	
  da	
  un	
  “persistent	
  store	
  coordinator”	
  
                         che	
  si	
  occupa	
  della	
  gestione	
  di	
  uno	
  o	
  più	
  sistemi	
  di	
  memorizzazione	
  persistente.	
  
                      c. L'ultimo	
   elemento	
   invece	
   prende	
   il	
   nome	
   di	
   “persistent	
   data	
   store”	
   ed	
   è	
   quello	
   che	
   si	
  
                         occupa	
   della	
   persistenza	
   della	
   memorizzazione	
   di	
   dati	
   creati	
   attraverso	
   il	
   “managed	
  
                         object	
  context”.	
  
	
  
	
  
          8. Il	
   frame	
   work	
   Foundation	
   fornisce	
   la	
   classe	
   NSXMLParser	
   che	
   ci	
   permette	
   di	
   utilizzare	
  
             l’interfaccia	
  SAX	
  (Simple	
  API	
  for	
  XML),	
  con	
  lo	
  scopo	
  di	
  recuperare	
  elementi	
  da	
  un	
  documento	
  
             XML,	
   leggendo	
   il	
   file	
   XML	
   linea	
   per	
   linea	
   e	
   basando	
   la	
   sua	
   lettura	
   su	
   eventi.	
  
             Al	
   verificarsi	
   di	
   un	
   evento	
   (ad	
   esempio:	
   apertura	
   di	
   un	
   tag,	
   chiusura	
   di	
   un	
   tag,	
   etc…)	
   viene	
  
             chiamata	
  una	
  funzione	
  specifica	
  ,	
  chiamata	
  altresì	
  “handler”,	
  che	
  può	
  gestirlo.	
  
             I	
  vantaggi	
  dell’interfaccia	
  SAX	
  sono	
  principalmente	
  legati	
  alla	
  velocità	
  e	
  all’utilizzo	
  di	
  memoria	
  
             mentre	
   presenta	
   un	
   unico	
   difetto:	
   è	
   possibile	
   solamente	
   la	
   lettura	
   del	
   file	
   xml	
   e	
   non	
   la	
   sua	
  
             scrittura.	
  	
  
          9. L'iPhone	
   OS,	
   in	
   questo	
   strato,	
   fornisce	
   un	
   insieme	
   di	
   interfacce	
   per	
   l'accesso	
   a	
   molte	
  
             funzionalità	
   di	
   basso	
   livello	
   del	
   sistema	
   operativo,	
   che	
   avvengono	
   attraverso	
   la	
   libreria	
  
             LibSystem.	
  	
  
	
  

2.2 Strumenti	
  di	
  sviluppo	
  disponibili	
  per	
  l’Iphone	
  
2.2.1 	
              Il	
  frame	
  work	
  Cocoa	
  
Il	
  Cocoa,	
  racchiude	
  i	
  frame	
  work	
  più	
  usati	
  nell'implementazione	
  di	
  un	
  programma	
  per	
  l'Iphone:	
  UIKit	
  e	
  
il	
   Foundation	
   permettono	
   un	
   accesso	
   da	
   parte	
   delle	
   applicazioni	
   agli	
   strati	
   sottostanti,	
   come	
  
rappresentato	
   in	
   Fig	
   1,	
   poiché	
   tipicamente	
   esiste	
   sempre	
   un	
   metodo	
   UIKit	
   oppure	
   una	
   funzione	
  
Foundation	
  corrispondente	
  per	
  una	
  chiamata	
  di	
  basso	
  livello.	
  	
  

Uno	
  dei	
  motivi	
  che	
  ha	
  consentito	
  la	
  sua	
  diffusione,	
  è	
  stato	
  la	
  sua	
  struttura	
  suddivisa	
  in:	
  	
  

       ⇒ Un	
  ambiente	
  di	
  runtime	
  
       ⇒ Un	
  ambiente	
  di	
  sviluppo	
  

A	
  runtime,	
  le	
  applicazioni	
  hanno	
  un'interfaccia	
  utente	
  ben	
  integrata	
  con	
  le	
  altre	
  parti	
  del	
  sistema	
  quali	
  
il	
   Finder	
   e	
   il	
   Dock	
   ad	
   esempio,	
   come	
   anche	
   l'ambiente	
   di	
   sviluppo	
   che	
   presenta	
   al	
   programmatore	
   una	
  
suite	
   integrata	
   di	
   parti	
   software	
   object-­‐oriented	
   che	
   permettono	
   di	
   creare	
   rapidamente	
   programmi	
  
robusti	
   e	
   ricchi	
   di	
   caratteristiche,	
   grazie	
   al	
   riutilizzo,	
   alla	
   modifica	
   e	
   al	
   riadattamento	
   delle	
   classi	
  
richieste	
  dall'applicativo.	
  

       	
                                                                                                                                                          2-­‐10	
  
Apple	
   comunque	
   consiglia	
   sempre	
   l'utilizzo	
   delle	
   classi	
   e	
   degli	
   oggetti	
   forniti	
   dal	
   frame	
   work,	
  
soprattutto	
  per	
  quanto	
  riguarda	
  l'approccio	
  alle	
  interfacce	
  grafiche.	
  

2.2.1.1 	
  Cocoa	
  nell’Iphone	
  OS	
  
In	
  linea	
  generica,	
  si	
  può	
  dire	
  che	
  il	
  sistema	
  di	
  librerie	
  e	
  frame	
  work	
  dell'Iphone	
  OS	
  è	
  un	
  sottoinsieme	
  
delle	
  librerie	
  e	
  dei	
  frame	
  work	
  di	
  Mac	
  OS-­‐X.	
  Le	
  caratteristiche	
  sulle	
  quali	
  si	
  differenziano	
  i	
  due	
  tipi	
  di	
  
Cocoa	
   sono	
   poche,	
   ma	
   importanti:	
   tra	
   quelle	
   più	
   rilevanti,	
   spiccano	
   la	
   mancanza	
   della	
   riga	
   di	
   comando	
  
per	
  accedere	
  ai	
  servizi	
  di	
  sistema	
  e	
  l'assenza	
  del	
  QuickTime	
  nella	
  piattaforma	
  mobile.	
  

2.2.2 	
  	
       La	
  piattaforma	
  SDK	
  
Con	
   l'introduzione	
   di	
   Xcode	
   3.1	
   e	
   dell'Iphone	
   OS,	
   si	
   è	
   anche	
   avuta	
   la	
   necessità	
   di	
   scegliere	
   la	
  
piattaforma	
   sulla	
   quale	
   sviluppare	
   tutti	
   i	
   software,	
   appunto	
   la	
   SDK,	
   se	
   riferita	
   al	
   sistema	
   Mac	
   OS-­‐X	
  
oppure	
  quella	
  riguardante	
  l'Iphone	
  OS.	
  

L'SDK	
   per	
   l'Iphone	
   include	
   gli	
   stessi	
   componenti	
   dell'Sdk	
   del	
   Mac	
   OS-­‐X,	
   ma	
   si	
   differisce	
   da	
   essa	
   in	
  
quanto	
   comprende	
   altri	
   tool	
   ed	
   un	
   compilatore	
   specifico	
   per	
   l'Iphone	
   OS	
   e	
   diversi	
   template	
   di	
   progetti	
  
specifici	
  per	
  le	
  diverse	
  piattaforme.	
  

2.2.3 	
           Xcode	
  
L'ambiente	
   di	
   sviluppo	
   per	
   applicazioni	
   Cocoa	
   non	
   è	
   unico,	
   è	
   possibile,	
   infatti,	
   sia	
   sviluppare	
   con	
  
applicazioni	
  fornite	
  da	
  Apple,	
  come	
  Xcode	
  e	
  Interface	
  Builder,	
  sia	
  utilizzare	
  software	
  di	
  terze	
  parti.	
  
Nonostante	
   ciò,	
   Xcode	
   e	
   Interface	
   Builder	
   sono	
   le	
   applicazioni	
   più	
   comunemente	
   utilizzate	
   per	
  
sviluppare	
   software	
   Cocoa:	
   presentano	
   il	
   motore	
   dell'ambiente	
   di	
   sviluppo	
   integrato	
   (IDE)	
   per	
  
applicazioni	
  in	
  Mac	
  OS	
  e	
  Iphone	
  OS.	
  
Xcode	
   è	
   così	
   diffuso	
   perché	
   possiede	
   i	
   set	
   di	
   strumenti	
   di	
   sviluppo	
   più	
   completo	
   permettendo	
   di	
  
gestire:	
  
     ⇒ La	
   creazione	
   dei	
   progetti,	
   indicando	
   l'SDK	
   richiesto,	
   i	
   requisiti	
   necessari,	
   le	
   dipendenze	
   e	
   le	
  
           configurazioni	
  strutturali.	
  
     ⇒ La	
  scrittura	
  del	
  codice	
  tramite	
  editor.	
  
     ⇒ La	
  compilazione	
  del	
  codice.	
  
     ⇒ Il	
  debug	
  del	
  progetto	
  in	
  maniera	
  remota	
  o	
  locale	
  sul	
  simulatore	
  dell'Iphone	
  OS	
  
	
  
Permette	
   inoltre	
   di	
   compilare	
   progetti	
   da	
   codice	
   sorgente	
   scritto	
   in	
   C,	
   C++,	
   Objective	
   C,	
   generando	
  
eseguibili	
   e	
   tutti	
   i	
   tipi	
   di	
   software	
   supportati	
   da	
   Mac	
   OS-­‐X,	
   compresi	
   strumenti	
   da	
   riga	
   di	
   comando,	
  
frame	
   work,	
   estensioni	
   del	
   kernel,	
   bundle	
   e	
   applicazioni;	
   mentre	
   per	
   l'Iphone	
   sono	
   solo	
   possibili	
  
applicazioni	
  eseguibili.	
  
Essendo	
   specifico	
   per	
  applicazioni	
   Cocoa	
   e	
   in	
   questo	
   caso	
   usato	
   per	
   lo	
   sviluppo	
   di	
   un’applicazione	
   per	
  
Iphone,	
  permette	
  di	
  scegliere	
  quale	
  tipo	
  di	
  modello	
  creare,	
  come	
  mostrato	
  nella	
  figura	
  sottostante.	
  
	
  




      	
                                                                                                                                                        2-­‐11	
  
 
Figura	
  2:	
  sviluppo	
  di	
  applicazioni	
  Cocoa	
  

2.2.4 	
           Interface	
  Builder	
  
La	
   seconda	
   applicazione	
   come	
   importanza	
   nei	
   progetti	
   Cocoa	
   è	
   l'Interface	
   Builder,	
   uno	
   strumento	
  
grafico	
  nato	
  per	
  la	
  creazione	
  delle	
  interfacce	
  grafiche	
  che	
  è	
  integrato	
  con	
  Xcode,	
  e	
  che	
  permette	
  quindi	
  
allo	
  stesso	
  programma	
  di	
  riconoscere	
  le	
  eventuali	
  modifiche	
  svolte	
  dal	
  programmatore	
  nel	
  codice	
  del	
  
progetto	
  e	
  riportarle	
  così	
  nell'interfaccia	
  grafica.	
  
I	
  quattro	
  principali	
  elementi	
  che	
  contraddistinguono	
  la	
  struttura	
  dell'Interface	
  Builder	
  sono:	
  
	
  
       ⇒ Nib	
  file	
  
       ⇒ L'inspector	
  
       ⇒ Object	
  library	
  
       ⇒ Connections	
  panel	
  


2.2.4.1 	
   Nib	
  file	
  
Un	
   Nib	
   file	
   è	
   un	
   contenitore	
   che	
   include	
   gli	
   oggetti	
   che	
   compaiono	
   nell'interfaccia	
   utente	
   in	
   una	
   forma	
  
di	
  archivio,	
  e	
  le	
  relative	
  informazioni,	
  comprese	
  la	
  posizione,	
  la	
  dimensione	
  e	
  i	
  dati	
  riguardanti	
  le	
  classi	
  
personalizzate,	
   in	
   modo	
   da	
   poter	
   permettere	
   all'interface	
   builder	
   di	
   ricostruire	
   l'interfaccia	
   grafica	
  
anche	
  dopo	
  la	
  sua	
  creazione.	
  	
  
L'Interface	
   Builder,	
   visualizzerà	
   il	
   suo	
   contenuto	
   in	
   una	
   finestra	
   del	
   documento	
   che	
   permetterà	
   di	
  
accedere	
   agli	
   oggetti	
   del	
   file	
   come	
   finestre,	
   menù,	
   object	
   controller,	
   e	
   che	
   collegherà	
   gli	
   oggetti	
   delle	
  
interfacce	
   utente	
   con	
   i	
   modelli	
   che	
   rappresentano	
   i	
   dati	
   delle	
   applicazioni,	
   fornendo	
   oltretutto	
   la	
  
gestione	
  globale	
  dell'applicazione	
  da	
  sviluppare.	
  
	
  

2.2.4.2 	
   	
  L'inspector	
  
Include	
  alcuni	
  riquadri	
  selezionabili	
  per	
  impostare	
  la	
  configurazione	
  iniziale	
  di	
  runtime	
  degli	
  oggetti	
  
(anche	
  se	
  le	
  dimensioni	
  e	
  altri	
  attributi	
  possono	
  essere	
  manipolati	
  direttamente).	
  
	
  




      	
                                                                                                                                                         2-­‐12	
  
2.2.4.3 	
   	
  Object	
  Library	
  
Contiene	
  gli	
  oggetti	
  che	
  l'interfaccia	
  utente	
  può	
  racchiudere,	
  comprendendo	
  sia	
  gli	
  oggetti	
  tipici	
  (come	
  
finestre,	
  controlli,	
  menu,	
  text	
  view)	
  che	
  i	
  controller	
  di	
  oggetti,	
  viste	
  personalizzate	
  di	
  oggetti,	
  oppure	
  
frame	
  work	
  come	
  ad	
  esempio,	
  l'Image	
  Kit.	
  
L'Object	
   Library	
   raggruppa	
   oggetti	
   per	
   categorie,	
   facilitando	
   la	
   navigazione	
   e	
   permettendo	
   al	
  
programmatore	
  una	
  più	
  facile	
  ricerca	
  di	
  elementi	
  grafici	
  specifici.	
  	
  
L'Interface	
   Builder	
   creerà	
   un'istanza	
   predefinita	
   di	
   un	
   oggetto	
   solo	
   trascinandolo	
   dalla	
   libreria	
  
all'interfaccia,	
  	
  in	
  modo	
  da	
  consentire	
  lo	
  sviluppatore	
  di	
  poterlo	
  configurare	
  e	
  collegare	
  ad	
  altri	
  oggetti	
  
utilizzando	
  la	
  finestra	
  Inspector.	
  


2.2.4.4 	
   Connections	
  panel	
  
Permette	
   di	
   visualizzare	
   le	
   connessioni	
   legate	
   a	
   un	
   oggetto	
   selezionato	
   nella	
   finestra	
   di	
   Interface	
  
Builder,	
  riferita	
  alla	
  view	
  da	
  modificare.	
  È	
  possibile	
  quindi,	
  attraverso	
  questo	
  pannello,	
  visualizzare	
  e	
  
gestire	
  tutte	
  le	
  connessioni	
  dell'oggetto	
  selezionato.	
  
Qui	
  di	
  seguito	
  sono	
  riportate	
  le	
  immagini	
  che	
  descrivono	
  gli	
  elementi	
  sopraelencati.	
  
	
  




                                                                                                                                                           	
  




                                            	
                                                             	
  
Figura	
  3:	
  Da	
  sinistra	
  -­	
  l'Inspector,	
  l'Object	
  Library,	
  Connections	
  Panel	
  




      	
                                                                                                                                           2-­‐13	
  
2.2.5 	
            Iphone	
  OS	
  simulator	
  
La	
   Apple	
   prevedendo	
   l’installazione	
   dei	
   programmi	
   sull’Iphone	
   solamente	
   dietro	
   il	
   pagamento	
   di	
   un	
  
abbonamento	
   annuale	
   di	
   99$/anno	
   oppure	
   299$/anno,	
   ha	
   previsto	
   nel	
   tool	
   di	
   sviluppo	
   per	
   i	
  
programmatori,	
  anche	
  uno	
  strumento	
  per	
  il	
  test	
  dei	
  programmi	
  chiamato	
  Iphone	
  Simulator	
  il	
  cui	
  scopo	
  
è	
  quello	
  di	
  simulare	
  il	
  funzionamento	
  del	
  vero	
  e	
  proprio	
  dispositivo.	
  
Esso,	
   consente	
   allo	
   sviluppatore	
   di	
   poter	
   testare	
   ed	
   eventualmente	
   eseguire	
   il	
   debug	
   del	
   suo	
  
programma	
   sul	
   computer,	
   prima	
   di	
   installarlo	
   sull’Iphone,	
   abilitando	
   l’uso	
   dell’interfaccia	
   utente	
  
multitouch	
  presente	
  nella	
  realtà.	
  
Durante	
  la	
  fase	
  di	
  test,	
  comunque,	
  lo	
  sviluppatore	
  dovrà	
  sempre	
  tenere	
  conto	
  che	
  la	
  simulazione	
  non	
  
sarà	
   proprio	
   reale	
   al	
   100%	
   poiché	
   il	
   touch	
   pad	
   del	
   computer	
   sostituirà,	
   di	
   fatto,	
   il	
   touch	
   dell’Iphone	
  
rendendo	
   impossibile	
   il	
   test	
   delle	
   interfacce	
   multitouch,	
   oppure	
   l’utilizzo	
   da	
   parte	
   del	
   simulatore	
   delle	
  
librerie	
   Foundation	
   e	
   Core	
   Foundation	
   presenti	
   nel	
   MAC	
   OS	
   anziché	
   di	
   quelle	
   utilizzate	
   dall’Iphone	
  
nella	
  realtà.	
  
Sarà	
   inoltre	
   importante	
   tenere	
   in	
   considerazione	
   un	
   ultimo	
   elemento:	
   le	
   prestazioni	
   del	
   programma	
  
che	
   sull’Iphone	
   simulator	
   saranno	
   notevolmente	
   più	
   veloci	
   poiché	
   il	
   simulatore	
   eseguirà	
   le	
  
applicazioni	
  come	
  ospiti	
  del	
  MAC	
  OS	
  X,	
  quindi	
  sfruttando	
  il	
  processore	
  del	
  MacBook	
  e	
  la	
  sua	
  ram.	
  
	
  
	
  

2.3 Objective-­‐C	
  
Tale	
   linguaggio	
   è	
   diventato	
   il	
   più	
   orientato	
   per	
   lo	
   sviluppo	
   di	
   applicazioni	
   per	
   sistemi	
   Mac	
   OS	
   X	
   e	
  
iPhone	
   OS,	
   nascendo	
   dall'esigenza	
   di	
   estendere	
   alla	
   programmazione	
   ad	
   oggetti	
   il	
   linguaggio	
   C.	
   Le	
   sue	
  
caratteristiche	
  possono	
  essere	
  le	
  seguenti:	
  
	
  
     ⇒ La	
  struttura	
  è	
  meno	
  tipizzata	
  di	
  C++.	
  	
  
     ⇒ E’	
  basato	
  sullo	
  scambio	
  di	
  messaggi	
  e	
  su	
  di	
  un’estrema	
  dinamicità.	
  
     ⇒ In	
  fase	
  di	
  esecuzione	
  fornisce	
  un	
  maggior	
  supporto	
  run-­‐time	
  alla	
  riflessione	
  rispetto	
  a	
  C++.	
  
     ⇒ 	
  E’	
  più	
  orientato	
  verso	
  decisioni	
  “dinamiche”	
  rispetto	
  al	
  C++.	
  
	
  

2.3.1 Oggetti,	
  classi,	
  metodi	
  e	
  istanze	
  
Un	
   programma	
   orientato	
   a	
   oggetti	
   è	
   generalmente	
   costituito	
   da	
   una	
   diversità	
   di	
   oggetti	
   che	
  
interagiscono	
  tra	
  loro	
  e	
  che	
  sono	
  dichiarati	
  tramite	
  la	
  definizione	
  della	
  loro	
  classe.	
  
Si	
   potrà	
   definire	
   un	
   oggetto	
   come	
   composto	
   principalmente	
   da	
   una	
   variabile	
   istanziata	
   (dato)	
   che	
  
rappresenterà	
   lo	
   stato	
   di	
   un	
   oggetto	
   e	
   da	
   funzioni	
   che	
   agiranno	
   sulle	
   variabili	
   come	
   risposta	
   a	
  
messaggi.	
   Un	
   oggetto	
   quindi	
   potrà	
   essere	
   visto	
   come	
   un	
   semplice	
   programma	
   da	
   chiamare	
  
mandandogli	
  un	
  messaggio	
  per	
  eseguire	
  una	
  semplice	
  azione.	
  
La	
   classe	
   invece	
   potrà	
   essere	
   definita	
   come	
   il	
   prototipo	
   di	
   un	
   determinato	
   tipo	
   di	
   oggetto,	
   dichiarando	
  
le	
  variabili	
  d’istanza	
  che	
  fanno	
  parte	
  di	
  ogni	
  membro	
  della	
  classe	
  e	
  definendo	
  un	
  insieme	
  di	
  metodi	
  che	
  
tutti	
  gli	
  oggetti	
  della	
  classe	
  possono	
  usare.	
  
Il	
  compilatore,	
  quando	
  dovrà	
  produrre	
  gli	
  eseguibili	
  del	
  programma,	
  creerà	
  un	
  solo	
  oggetto	
  accessibile	
  
per	
   ogni	
   classe	
   detto	
   “class	
   object”,	
   che	
   avrà	
   lo	
   scopo	
   di	
   generare	
   nuovi	
   oggetti	
   appartenenti	
   alla	
  
classe.	
  	
  
Il	
   “class	
   object”	
   sarà	
   quindi	
   la	
   versione	
   compilata	
   della	
   classe,	
   e	
   gli	
   oggetti	
   che	
   creerà	
   saranno	
   le	
  
istanze	
  della	
  classe	
  al	
  tempo	
  di	
  esecuzione.	
  
	
  

2.3.2 Interfacce	
  e	
  implementazioni	
  
L’	
   Objective-­‐C	
   richiede	
   che	
   l'interfaccia	
   e	
   l'implementazione	
   di	
   una	
   classe	
   siano	
   dichiarati	
   in	
   blocchi	
   di	
  
codice	
   differenti.	
   Per	
   convenzione,	
   l'interfaccia	
   è	
   messa	
   in	
   un	
   file	
   con	
   estensione	
   “.h”,	
   mentre	
  
l'implementazione	
  va	
  scritta	
  in	
  un	
  file	
  con	
  suffisso	
  “.m”.	
  
	
  




      	
                                                                                                                                                         2-­‐14	
  
2.3.2.1 	
   Interfacce	
  
L'interfaccia	
  di	
  una	
  classe	
  è	
  solitamente	
  definita	
  in	
  un	
  file	
  “.h”.	
  
Sfruttando	
  la	
  convenzione	
  di	
  assegnare	
  il	
  nome	
  del	
  file	
  basandosi	
  su	
  quello	
  della	
  classe,	
  un	
  prototipo	
  di	
  
classe	
  potrà	
  essere	
  il	
  seguente:	
  	
  
	
  
            #import "NomeDellaSuperclasse.h"
            @interface NomeDellaClasse : NomeDellaSuperclasse
            {
            //variabili d'istanza
            int variabileIntera;
            float variabileFloat;
            ...
            }
            //metodi di classe
            + metodoDiClasse1
            + metodoDiClasse2
            + ...
            //metodi d’istanza
            - metodoDiIstanza1
            - metodoDiIstanza2
            - ...
            @end
	
  
Tabella	
  1:	
  codice	
  esempio	
  dell’interfaccia	
  NomeDellaClasse.h	
  

Il	
   segno	
   meno	
   (-­‐)	
   denota	
   i	
   metodi	
   d’istanza,	
   mentre	
   il	
   segno	
   (+)	
   più	
   quello	
   di	
   classe	
   (analoghi	
   alle	
  
funzioni	
  statiche	
  del	
  C++).	
  
	
  

2.3.2.2 	
   Implementazioni	
  
L'interfaccia	
  dichiara	
  solamente	
  i	
  prototipi	
  dei	
  metodi	
  e	
  non	
  la	
  loro	
  implementazione.	
  La	
  convenzione	
  
è	
  la	
  medesima	
  dell’interfaccia.	
  	
  
I	
  metodi	
  sono	
  funzionalità	
  che	
  una	
  classe	
  può	
  offrire	
  e	
  ne	
  esistono	
  di	
  due	
  tipi:	
  quelli	
  ereditati	
  dalle	
  
classi	
  da	
  cui	
  discende	
  e	
  quelli	
  aggiunti.	
  
Tra	
   i	
   metodi	
   aggiunti	
   va	
   notato	
   che	
   sono	
   pubblici	
   tutti	
   quelli	
   richiamati	
   nell'interfaccia	
   della	
   classe	
   cui	
  
appartengono	
   (file	
   con	
   estensione	
   .h);	
   sono	
   invece	
   privati	
   quei	
   metodi	
   implementati	
   direttamente	
  
nella	
  descrizione	
  della	
  classe	
  (file	
  con	
  estensione	
  .m.).	
  Un	
  metodo	
  che	
  può	
  essere	
  usato	
  da	
  un’istanza	
  
della	
   classe	
   viene	
   preceduto	
   dal	
   segno	
   “-­‐”	
   e	
   può	
   essere	
   usato	
   solo	
   in	
   presenza	
   di	
   una	
   istanza.	
   Un	
  
metodo	
   che	
   invece	
   è	
   usato	
   indipendentemente	
   dalle	
   istanze	
   dalla	
   classe	
   viene	
   preceduto	
   dal	
   segno	
   “+”	
  
e	
  chiamato	
  “metodo	
  di	
  classe”.	
  
Una	
   nota	
   da	
   porre	
   riguarda	
   l'ereditarietà:	
   è	
   sempre	
   possibile	
   considerare	
   le	
   definizioni	
   di	
   classe	
   come	
  
additive,	
  poiché	
  dichiarare	
  una	
  classe,	
  significa	
  aggiungere	
  metodi	
  alla	
  classe	
  da	
  cui	
  deriva.	
  
	
  
#import "NomeDellaClasse.h"
      @implementation NomeDellaClasse
     + metodoDiClasse1 {
       // implementazione
     }
     + metodoDiClasse2 {

       	
                                                                                                                                                           2-­‐15	
  
// implementazione
        }
 ...
- metodoDiIstanza1 {
      // implementazione
     ... }
 - metodoDiIstanza2 {
     // implementazione
    ... }
...
@end	
  
Codice	
  1:	
  Implementazione	
  della	
  classe	
  NomeDellaClasse	
  

	
  

2.3.3 Messaggi	
  e	
  polimorfismo	
  
In	
   Objective	
   C	
   è	
   possibile,	
   una	
   volta	
  creata	
   un'istanza	
   dell'oggetto,	
   inviargli	
   uno	
   o	
   più	
   messaggi,	
   con	
   lo	
  
scopo	
  ad	
  esempio	
  di	
  implementare	
  dei	
  metodi	
  appartenenti	
  a	
  quell'oggetto.	
  
Una	
   volta	
   che	
   l'oggetto	
   ha	
   svolto	
   il	
   suo	
   compito,	
   è	
   necessario	
   rilasciarlo	
   (attraverso	
   il	
   messaggio	
  
release)	
   poiché	
   per	
   la	
   sua	
   creazione	
   è	
   stata	
   occupata	
   della	
   memoria	
   che	
   potrebbe	
   servire	
   per	
   nuovi	
  
oggetti.	
  
I	
  messaggi	
  scambiati	
  sono	
  dotati	
  di	
  alcune	
  caratteristiche	
  particolari:	
  un	
  oggetto	
  può	
  essere	
  utilizzato	
  
soltanto	
   da	
   alcuni	
   metodi	
   che	
   gli	
   sono	
   associati	
   e	
   non	
   è	
   possibile	
   quindi	
   mischiare	
   i	
   metodi	
   tra	
   oggetti	
  
anche	
  se	
  hanno	
  lo	
  stesso	
  nome,	
  permettendo	
  a	
  oggetti	
  diversi	
  di	
  rispondere	
  allo	
  stesso	
  messaggio	
  in	
  
modo	
  differente.	
  	
  
Questa	
   caratteristica,	
   descritta	
   come	
   polimorfismo,	
   svolge	
   un	
   ruolo	
   rilevante	
   nella	
   progettazione	
   di	
  
programmi	
  Objective-­‐C.	
  
Insieme	
  alla	
  caratteristica	
  di	
  dinamicità,	
  in	
  particolare	
  il	
  binding	
  dinamico,	
  è	
  possibile	
  scrivere	
  codice	
  
che	
   potrebbe	
   essere	
   applicato	
   a	
   un	
   numero	
   qualsiasi	
   di	
   oggetti,	
   senza	
   dover	
   scegliere	
   al	
   momento	
  
dell'implementazione.	
   È	
   possibile	
   implementare	
   quindi	
   un	
   metodo	
   che	
   invia	
   un	
   messaggio	
   a	
   un	
  
oggetto	
  id,	
  consentendo	
  potenzialmente	
  quindi	
  a	
  tutti	
  gli	
  oggetti	
  di	
  ricevere	
  tale	
  messaggio.	
  
	
  

2.3.4 	
            Objective-­‐C	
  e	
  oggetti	
  Cocoa	
  
Cocoa	
  è	
  strutturalmente	
  orientato	
  agli	
  oggetti,	
  dai	
  suoi	
  paradigmi	
  e	
  meccanismi,	
  all'architettura	
  event-­‐
driven,	
  e	
  una	
  delle	
  sue	
  peculiarità	
  è	
  di	
  essere	
  improntato	
  allo	
  scambio	
  di	
  messaggi,	
  caratteristica	
  che	
  
gli	
  restituisce	
  un	
  elevato	
  dinamismo.	
  
Quando	
   un	
   oggetto	
   è	
   creato,	
   la	
   memoria	
   è	
   allocata	
   e	
   le	
   sue	
   variabili	
   d’istanza	
   inizializzate;	
   cosicché	
  
ogni	
   oggetto	
   creato	
   nasconde	
   una	
   struttura	
   dati	
   il	
   cui	
   primo	
   membro	
   è	
   il	
   puntatore(isa)	
   che	
   punta	
   alla	
  
classe	
  dell'oggetto	
  che	
  possiede,	
  il	
  quale	
  a	
  sua	
  volta	
  dispone	
  dei	
  puntatori	
  alle	
  proprie	
  super	
  classi.	
  
Attraverso	
   questa	
   catena	
   di	
   riferimenti,	
   un	
   oggetto	
   ha	
   accesso	
   a	
   tutti	
   i	
   metodi	
   implementati	
   dalla	
  
propria	
   classe	
   e	
   dalla/e	
   superclasse/i.	
   Il	
   puntatore	
   è	
   l’elemento	
   fondamentale	
   per	
   il	
   meccanismo	
   di	
  
distribuzione	
   dei	
   messaggi	
   e	
   per	
   il	
   dinamismo	
   degli	
   oggetti	
   Cocoa.	
   Questa	
   visione	
   degli	
   oggetti	
  
semplifica	
   notevolmente	
   cosa	
   accade	
   a	
   runtime	
   nell’Objective-­‐C	
   per	
   la	
   distribuzione	
   dei	
   messaggi,	
   le	
  
gerarchie	
  e	
  altre	
  caratteristiche	
  generali	
  di	
  comportamento	
  degli	
  oggetti.	
  	
  
	
  

2.3.5 Dinamicità	
  dell’Objective-­‐C	
  
Objective-­‐C	
   è	
   un	
   linguaggio	
   molto	
   dinamico,	
   poiché	
   sposta	
   molta	
   della	
   responsabilità	
   di	
   risoluzione	
  
simbolica	
  dal	
  tempo	
  di	
  compilazione	
  al	
  tempo	
  di	
  runtime,	
  quando	
  il	
  controllo	
  è	
  dell'utente.	
  	
  
Esso	
  presenta	
  le	
  seguenti	
  tre	
  caratteristiche	
  di	
  dinamicità:	
  

       	
                                                                                                                                                             2-­‐16	
  
⇒ Tipizzazione	
  dinamica	
  (Dynamic	
  typing),	
  determinando	
  la	
  classe	
  di	
  un	
  oggetto	
  a	
  runtime	
  
       ⇒ Invocazione	
   dinamica(Dynamic	
   binding)	
   dei	
   metodi,	
   determinando	
   il	
   metodo	
   da	
   invocare	
   a	
  
         runtime	
  
       ⇒ Caricamento	
  dinamico(Dynamic	
  loading)	
  aggiungendo	
  nuovi	
  moduli	
  ad	
  un	
  software	
  a	
  runtime.	
  
	
  
Per	
  la	
  tipizzazione	
  dinamica,	
  Objective-­‐C	
  introduce	
  il	
  tipo	
  id,	
  che	
  può	
  rappresentate	
  ogni	
  tipologia	
  di	
  
oggetto	
   e	
   rende	
   possibile	
   la	
   sostituzione	
   di	
   oggetti	
   a	
   runtime,	
   lasciando	
   ad	
   altri	
   fattori	
   in	
   fase	
   di	
  
esecuzione	
  la	
  scelta	
  di	
  quale	
  tipo	
  di	
  oggetto	
  inserire	
  nel	
  codice.	
  	
  
Tale	
  tipizzazione	
  permette	
  associazioni	
  tra	
  gli	
  oggetti	
  da	
  determinare	
  in	
  fase	
  di	
  esecuzione,	
  piuttosto	
  
che	
  forzarli	
  nel	
  codice	
  in	
  una	
  struttura	
  statica.	
  I	
  tipi	
  statici	
  garantiscono	
  al	
  tempo	
  di	
  compilazione	
  una	
  
maggiore	
  integrità	
  dei	
  dati,	
  offrendo	
  una	
  più	
  elevata	
  flessibilità.	
  	
  
E'	
   possibile	
   comunque	
   verificare	
   il	
   tipo	
   di	
   oggetto	
   a	
   runtime,	
   determinando	
   la	
   sua	
   idoneità	
   per	
  
particolari	
  operazioni,	
  rendendo	
  comunque	
  anche	
  possibile	
  la	
  definizione	
  degli	
  oggetti	
  staticamente.	
  
Il	
  tutto,	
  ha	
  lo	
  scopo	
  di	
  garantire	
  robustezza	
  all'invocazione	
  dinamica	
  di	
  metodi.	
  
L’invocazione	
  dinamica,	
  rimanda	
  così	
  la	
  decisione	
  del	
  metodo	
  da	
  utilizzare	
  al	
  tempo	
  di	
  esecuzione.	
  La	
  
chiamata	
  del	
  metodo	
  avviene	
  quindi	
  non	
  al	
  tempo	
  di	
  compilazione	
  ma	
  proprio	
  quando	
  un	
  messaggio	
  è	
  
stato	
   recapitato.	
   Con	
   queste	
   due	
   caratteristiche	
   di	
   dinamicità	
   è	
   possibile	
   quindi	
   ottenere	
   diversi	
  
risultati	
  ogni	
  volta	
  che	
  si	
  esegue	
  il	
  codice.	
  	
  
Quando	
   un	
   messaggio	
   è	
   inviato	
   a	
   un	
   oggetto	
   tipizzato	
   dinamicamente,	
   il	
   sistema	
   a	
   runtime	
   usa	
   il	
  
puntatore	
  del	
  ricevitore	
  per	
  determinare	
  la	
  classe	
  dell'oggetto	
  e	
  da	
  lì	
  il	
  metodo	
  da	
  invocare,	
  cosicché	
  
esso	
  è	
  legato	
  dinamicamente	
  al	
  messaggio.	
  	
  
Nel	
   codice,	
   inoltre,	
   non	
   bisogna	
   aggiungere	
   nulla	
   per	
   beneficiare	
   della	
   dinamica	
   dei	
   metodi	
   invocati,	
  
perché	
  il	
  tutto	
  avviene	
  in	
  trasparenza	
  nel	
  momento	
  in	
  cui	
  è	
  inviato	
  un	
  messaggio,	
  a	
  maggior	
  ragione	
  se	
  
l'oggetto	
  è	
  tipizzato	
  dinamicamente.	
  
Il	
   caricamento	
   dinamico	
   è	
   la	
   caratteristica	
   di	
   Cocoa	
   che	
   dipende	
   da	
   Objective-­‐C	
   per	
   il	
   supporto	
  
runtime.	
   Grazie	
   al	
   caricamento	
   dinamico	
   un	
   programma	
   Cocoa	
   può	
   caricare	
   codice	
   eseguibile	
   e	
   le	
  
risorse	
  necessarie	
  quando	
  ne	
  ha	
  bisogno,	
  senza	
  doverlo	
  fare	
  al	
  momento	
  del	
  lancio.	
  Il	
  codice	
  eseguibile	
  
(collegato	
   prima	
   del	
   caricamento)	
   spesso	
   contiene	
   nuove	
   classi	
   che	
   sono	
   integrate	
   nell'immagine	
  
runtime	
  del	
  programma.	
  Sia	
  il	
  codice	
  sia	
  le	
  risorse	
  localizzate	
  (incluso	
  il	
  nib	
  file)	
  sono	
  contenuti	
  in	
  un	
  
bundle	
  e	
  sono	
  caricate	
  esplicitamente	
  da	
  metodi	
  definiti	
  nella	
  classe	
  NSBundle	
  di	
  Foundation.	
  
Questo	
   tipo	
   di	
   caricamento	
   di	
   codice	
   e	
   risorse	
   ottimizzano	
   le	
   prestazioni	
   diminuendo	
   la	
   memoria	
  
richiesta	
  dal	
  sistema,	
  con	
  la	
  conseguenza	
  che	
  le	
  applicazioni	
  diventano	
  estensibili.	
  	
  
Altro	
  effetto	
  è	
  la	
  possibilità	
  di	
  aggiungere	
  un'architettura	
  di	
  plug-­‐in	
  alle	
  applicazioni,	
  permettendo	
  così	
  
agli	
   sviluppatori	
   di	
   personalizzare	
   il	
   software	
   con	
   moduli	
   aggiuntivi	
   che	
   l'applicazione	
   può	
   caricare	
  
molto	
   tempo	
   dopo	
   il	
   suo	
   rilascio,	
   ammettendo	
   però	
   che	
   il	
   design	
   sia	
   coerente	
   e	
   che	
   le	
   classi	
   non	
  
entrino	
  in	
  conflitto.	
  
	
  

2.3.6 Le	
  classi	
  root	
  
Il	
   linguaggio	
   Objective-­‐C	
   e	
   il	
   sistema	
   runtime	
   non	
   sono	
   sufficienti	
   per	
   costruire	
   un	
   programma	
  
orientato	
  a	
  oggetti;	
  manca	
  una	
  definizione	
  dell'interfaccia	
  comune	
  a	
  tutti	
  gli	
  oggetti,	
  ed	
  è	
  per	
  questo	
  
motivo	
  che	
  deve	
  essere	
  utilizzata	
  la	
  classe	
  root.	
  	
  
Una	
   classe	
   root,	
   in	
   senso	
   generico	
   è	
   chiamata	
   così	
   perché	
   è	
   la	
   radice	
   di	
   una	
   gerarchia	
   di	
   classi,	
   non	
  
deriva	
  da	
  nessun'altra	
  classe,	
  e	
  in	
  questo	
  caso	
  è	
  alla	
  base	
  della	
  classe	
  gerarchica	
  Cocoa.	
  
Le	
  due	
  classi	
  di	
  tipo	
  root	
  che	
  sono	
  fornite	
  da	
  Cocoa	
  s’identificano	
  in:	
  
	
  	
  
         ⇒ NSObject	
  	
  
         ⇒ NSProxy	
  

       	
                                                                                                                                                              2-­‐17	
  
 
Un'osservazione	
  importante	
  va	
  fatta	
  riguardo	
  la	
  classe	
  NSProxy	
  in	
  quanto	
  quest'ultima	
  è	
  definita	
  come	
  
una	
   superclasse	
   astratta	
   per	
   gli	
   oggetti	
   che	
   agiscono	
   come	
   supporto	
   ad	
   altri	
   oggetti	
   ed	
   è	
   essenziale	
  
nelle	
   architetture	
   di	
   oggetti	
   distribuiti.	
   Tale	
   ruolo	
   è	
   molto	
   specializzato	
   ed	
   è	
   poco	
   frequente	
   nei	
  
programmi	
  Cocoa,	
  dove	
  la	
  maggior	
  parte	
  delle	
  volte	
  si	
  fa	
  riferimento	
  alla	
  classe	
  root	
  NSObject.	
  
Fondamentali	
  sono	
  le	
  dichiarazioni	
  dei	
  metodi	
  per	
  l'assegnazione,	
  l'inizializzazione,	
  l'introspector,	
  la	
  
gestione	
  della	
  memoria	
  e	
  il	
  supporto	
  al	
  runtime,	
  concetti	
  fondamentali	
  per	
  la	
  comprensione	
  di	
  Cocoa.	
  
	
  

2.3.6.1 	
   NSObject	
  
NSObject	
  non	
  ha	
  una	
  super	
  classe:	
  da	
  essa	
  derivano	
  molte	
  classi	
  Objective-­‐C	
  che	
  ereditano	
  l'interfaccia	
  
base	
  al	
  sistema	
  runtime	
  per	
  il	
  linguaggio	
  Objective-­‐C	
  e	
  le	
  sue	
  istanze	
  ottengono	
  le	
  funzionalità	
  tali	
  da	
  
diventare	
  oggetti.	
  	
  
Anche	
   se	
   non	
   è	
   strettamente	
   una	
   classe	
   astratta	
   NSObject	
   lo	
   è	
   virtualmente:	
   infatti	
   un	
   oggetto	
  
NSObject	
  non	
  può	
  fare	
  nulla	
  di	
  utile	
  al	
  di	
  là	
  di	
  essere	
  un	
  semplice	
  oggetto.	
  	
  
Per	
   aggiungere	
   gli	
   attributi	
   e	
   le	
   funzionalità	
   del	
   programma	
   specifico	
   è	
   necessario	
   creare	
   una	
   o	
   più	
  
classi	
  ereditate	
  da	
  NSObject	
  o	
  da	
  qualsiasi	
  altra	
  classe	
  derivata:	
  in	
  pratica	
  NSObject	
  adotta	
  il	
  protocollo	
  
NSObject	
  che	
  abilita	
  l'uso	
  di	
  oggetti	
  root.	
  	
  
	
  

2.3.7 	
            Allocazione	
  e	
  rilascio	
  degli	
  oggetti	
  
Objective-­‐C,	
  con	
  il	
  rilascio	
  di	
  Mac	
  OS	
  X	
  10.5,	
  ha	
  iniziato	
  ad	
  implementare	
  due	
  metodi	
  per	
  garantire	
  la	
  
persistenza	
  ed	
  il	
  rilascio	
  di	
  oggetti.	
  	
  
L'approccio	
   più	
   utilizzato	
   in	
   Mac	
   OS	
   X	
   10.5	
   è	
   la	
   “garbage	
   collection”:	
   il	
   sistema	
   di	
   runtime	
   rileva	
   gli	
  
oggetti	
   non	
   più	
   necessari	
   e	
   li	
   elimina	
   automaticamente,	
   risultando	
   anche	
   essere	
   la	
   più	
   semplice	
   da	
  
implementare	
  nella	
  maggior	
  parte	
  dei	
  casi.	
  
Il	
   secondo	
   approccio,	
   chiamato	
   “memory	
   management”,	
   si	
   basa	
   sul	
  conteggio	
   dei	
   riferimenti:	
   ciascuna	
  
chiamata	
   che	
   rivendica	
   la	
   proprietà	
   di	
   un	
   oggetto	
   (allocazione,	
   inizializzazione,	
   copia	
   e	
   trattenuta)	
  
deve	
   essere	
   bilanciata	
   da	
   una	
   chiamata	
   che	
   rimuove	
   tale	
   proprietà	
   (rilascio	
   e	
   autorilascio)	
   cosicché	
  
ogni	
   oggetto	
   ha	
   un	
   contatore	
   che	
   indica	
   il	
   numero	
   di	
   richieste	
   che	
   riceve	
   e	
   quando	
   tale	
   contatore	
  
decresce	
  fino	
  a	
  0,	
  l'oggetto	
  è	
  deallocato	
  e	
  la	
  memoria	
  occupata	
  viene	
  liberata.	
  
Il	
   metodo	
   analizzato	
   più	
   attentamente,	
   sarà	
   quest'ultimo,	
   poiché	
   è	
   quello	
   implementato	
   nell'Iphone	
  
OS.	
  
	
  

2.3.7.1 	
   Memory	
  management	
  
Nel	
   codice	
   Objective-­‐C	
   del	
   memory	
   management	
   un	
   oggetto	
   Cocoa	
   esiste	
   in	
   più	
   di	
   un	
   ciclo	
   di	
   vita	
   e	
  
potenzialmente	
  ha	
  diverse	
  fasi	
  di	
  vita	
  suddivise	
  nel	
  seguente	
  modo:	
  	
  
       1. Allocazione	
  in	
  memoria	
  
       2. Inizializzazione	
  
       3. Uso	
  
       4. Rilascio	
  	
  
       5. Distruzione	
  
Oltre	
  a	
  questi	
  importanti	
  punti,	
  va	
  ricordato	
  che	
  l'oggetto	
  inoltre	
  può	
  essere	
  sia	
  trattenuto	
  che	
  copiato.	
  	
  
Per	
  capire	
  questo	
  ciclo	
  di	
  vita,	
  bisogna	
  innanzitutto	
  sapere	
  che	
  ogni	
  oggetto	
  Cocoa	
  ha	
  associato	
  alla	
  sua	
  
esistenza	
   un	
   numero	
   intero,	
   chiamato	
   contatore	
   “retain”,	
   che	
   indica	
   il	
   numero	
   di	
   altri	
   oggetti	
   che	
   sono	
  
interessati	
  alla	
  sua	
  persistenza.	
  
In	
   seguito	
   all'allocazione,	
   l'oggetto	
   è	
   inizializzato	
   impostando	
   le	
   istanze	
   delle	
   sue	
   variabili	
   ad	
  
accettabili	
   valori	
   iniziali,	
   attraverso	
   la	
   dichiarazione	
   del	
   metodo	
   init	
   che	
   è	
   presente	
   nella	
   classe	
  
       	
                                                                                                                                                            2-­‐18	
  
NSObject	
   la	
   quale	
   lo	
   definisce	
   nel	
   suo	
   prototipo.	
   L'oggetto	
   è	
   così	
   pronto	
   per	
   essere	
   usato,	
   rendendo	
  
possibile	
  quindi	
  l'invio	
  di	
  messaggi,	
  oppure	
  ad	
  esempio	
  il	
  suo	
  invio	
  ad	
  altri	
  oggetti.	
  
Quando	
  si	
  rilascia	
  un	
  oggetto,	
  attraverso	
  un	
  messaggio	
  release,	
  NSObject	
  decrementa	
  il	
  suo	
  puntatore	
  
retain	
  e	
  se	
  tale	
  valore	
  diventa	
  zero	
  l'oggetto	
  viene	
  deallocato	
  in	
  due	
  fasi.	
  	
  
Nella	
   prima	
   fase,	
   il	
   metodo	
   dealloc	
   dell'oggetto	
   è	
   invocato	
   per	
   rilasciare	
   le	
   istanze	
   delle	
   variabili	
   e	
  
liberare	
   la	
   memoria	
   allocata	
   dinamicamente,	
   poi	
   successivamente	
   il	
   sistema	
   operativo	
   distrugge	
  
l'oggetto	
   e	
   reclama	
   la	
   memoria	
   che	
   era	
   occupata	
   dall'oggetto	
   stesso:	
   è	
   importante	
   notare	
   che	
   non	
   si	
  
dovrebbe	
  mai	
  invocare	
  direttamente	
  un	
  metodo	
  dealloc	
  di	
  un	
  oggetto.	
  
Nel	
   caso	
   in	
   cui,	
   ricevuto	
   un	
   oggetto,	
   si	
   richiede	
   il	
   suo	
   mantenimento,	
   il	
   contatore	
   retain	
   sarà	
  
incrementato	
   a	
   due	
   cosicché	
   saranno	
   quindi	
   necessari	
   due	
   messaggi	
   di	
   release	
   per	
   rilasciare	
   tale	
  
oggetto.	
  
In	
  un	
  programma	
  Objective-­‐C	
  è	
  possibile	
  ricevere	
  oggetti	
  da	
  altri	
  oggetti	
  e	
  inviarli	
  per	
  messaggio	
  ad	
  
altri	
   ancora.	
   Queste	
   caratteristiche	
   richiedono	
   che	
   se	
   un	
   primo	
   oggetto	
   invia	
   un	
   oggetto	
   a	
   un	
   terzo	
   che	
  
fa	
   da	
   ricevente,	
   il	
   primo	
   non	
   può	
   rilasciare	
   il	
   secondo	
   prematuramente	
   mentre	
   questo	
   è	
   utilizzato	
  
dall'ultimo	
  ricevente.	
  
Nel	
   caso	
   in	
   cui	
   il	
   ricevente	
   dell'oggetto	
   ha	
   bisogno	
   di	
   conservarlo	
   anche	
   quando	
   il	
   programma	
   ha	
  
terminato	
  il	
  suo	
  scopo,	
  può	
  farlo,	
  incrementando	
  il	
  contatore	
  retain.	
  	
  
In	
  tal	
  modo	
  se	
  il	
  creatore	
  dell'oggetto	
  lo	
  rilascia,	
  questo	
  non	
  sarà	
  deallocato	
  e	
  il	
  ricevente	
  diventerà	
  il	
  
responsabile	
  dello	
  stesso,	
  potendo	
  così	
  de	
  allocarlo	
  in	
  un	
  momento	
  successivo.	
  
In	
  una	
  tale	
  gestione,	
  si	
  potrebbe	
  verificare	
  un	
  problema	
  nel	
  suo	
  ciclo	
  di	
  vita:	
  
      ⇒ Se	
  un	
  oggetto	
  ne	
  crea	
  un	
  altro	
  e	
  poi	
  lo	
  invia	
  a	
  un	
  terzo,	
  il	
  primo	
  potrebbe	
  non	
  sapere	
  quando	
  
        poterlo	
   rilasciare	
   in	
   sicurezza,	
   poiché	
   ci	
   potrebbero	
   essere	
   infatti	
   molteplici	
   riferimenti	
  
        all'oggetto	
   nello	
   stack	
   delle	
   chiamate	
   che	
   risulterebbero	
   essere	
   sconosciute	
   alla	
   creazione	
  
        dell'oggetto.	
  	
  
Se	
   l'oggetto	
   creatore	
   lo	
   rilasciasse	
   e	
   altri	
   oggetti	
   inviassero	
   un	
   messaggio	
   a	
   quello	
   distrutto,	
   il	
  
programma	
  potrebbe	
  andare	
  in	
  crash.	
  	
  
La	
   soluzione	
   per	
   evitare	
   casi	
   di	
   questo	
   genere	
   è	
   stata	
   implementata	
   nel	
   Cocoa	
   introducendo	
   un	
  
meccanismo	
  per	
  dilazionare	
  la	
  deallocazione	
  chiamata	
  “autorelease”.	
  
Questa	
  è	
  un	
  meccanismo	
  che	
  si	
  avvale	
  dell'autorelease	
  pool	
  (definita	
  nella	
  classe	
  NSAutoreleasePool)	
  
che	
  può	
  essere	
  spiegata	
  come	
  una	
  collezione	
  di	
  oggetti	
  all'interno	
  di	
  un	
  ambito	
  definito	
  esplicitamente,	
  
contrassegnata	
   per	
   il	
   loro	
   eventuale	
   rilascio.	
   In	
   questa	
   situazione,	
   proprio	
   quando	
   s’invierà	
   un	
  
messaggio	
   di	
   autorilascio	
   a	
   un	
   oggetto	
   si	
   metterà	
   il	
   riferimento	
   all'oggetto	
   nell'autorelease	
   pool	
   del	
  
suo	
   ambito:	
   tale	
   oggetto	
   comunque	
   sarà	
   ancora	
   valido	
   cosicché	
   gli	
   altri	
   oggetti	
   che	
   rientreranno	
  
nell'ambito	
  dell'applicazione	
  definito	
  dall'autorelease	
  pool	
  potranno	
  comunque	
  inviargli	
  messaggi.	
  
Questo	
   metodo	
   è	
   comunque	
   sconsigliato	
   nell'Iphone	
   giacché	
   è	
   un	
   ambiente	
   che	
   ha	
   una	
   capacità	
   di	
  
memoria	
  limitata,	
  soprattutto	
  in	
  metodi	
  o	
  blocchi	
  di	
  codice	
  in	
  cui	
  si	
  creano	
  molti	
  oggetti.	
  
Si	
  potrà	
  quindi	
  sintetizzare	
  la	
  politica	
  di	
  proprietà	
  degli	
  oggetti	
  nella	
  seguente	
  maniera:	
  
      1. Nel	
  caso	
  di	
  allocazione	
  e	
  inizializzazione	
  di	
  un	
  oggetto,	
  si	
  sarà	
  proprietari	
  dello	
  stesso	
  fino	
  al	
  
         momento	
  del	
  suo	
  rilascio.	
  
      2. Se	
  l'oggetto	
  sarà	
  copiato,	
  si	
  sarà	
  comunque	
  responsabili	
  della	
  copia	
  e	
  del	
  suo	
  rilascio.	
  
      3. Se	
   si	
   trattiene	
   un	
   oggetto,	
   si	
   diventerà	
   parzialmente	
   proprietari	
   dello	
   stesso	
   e	
   si	
   dovrà	
  
         rilasciarlo	
  quando	
  non	
  servirà	
  più.	
  
      4. Al	
  contrario,	
  se	
  si	
  riceverà	
  da	
  un	
  altro	
  oggetto	
  un	
  oggetto,	
  non	
  si	
  diventerà	
  proprietari	
  e	
  non	
  lo	
  
         si	
  rilascerà.	
  
Per	
   la	
   corretta	
   scrittura	
   di	
   un	
   programma	
   in	
   quest’ambiente,	
   sarà	
   necessario	
   sicuramente	
   seguire	
  
queste	
   regole,	
   altrimenti	
   il	
   programma	
   potrebbe	
   richiedere	
   troppa	
   memoria	
   al	
   dispositivo	
   e	
   mandarlo	
  

      	
                                                                                                                                                         2-­‐19	
  
in	
   crash,	
   come	
   nel	
   caso	
   in	
   cui	
   ci	
   sia	
   l'invio	
   di	
   un	
   messaggio	
   a	
   un	
   oggetto	
   deallocato	
   in	
   maniera	
   non	
  
       controllata.	
  
       Queste	
  situazioni	
  in	
  linea	
  di	
  massima	
  dovrebbero	
  essere	
  evitate	
  attraverso	
  una	
  procedura	
  dettagliata	
  
       di	
  debug	
  del	
  programma.	
  

       2.3.7.1.1 	
   Allocazione	
  
       L'allocazione	
   permette	
   di	
   destinare	
   a	
   un	
   oggetto	
   Cocoa	
   una	
   porzione	
   di	
   memoria	
   virtuale	
   del	
  
       dispositivo	
  associata	
  al	
  programma.	
  

	
     Per	
  valutarne	
  la	
  sua	
  entità	
  si	
  prendono	
  in	
  considerazione	
  le	
  variabili	
  d’istanza	
  dell'oggetto,	
  inclusi	
  i	
  tipi	
  
       ed	
  il	
  loro	
  ordine,	
  come	
  specificato	
  dalla	
  classe	
  dell'oggetto.	
  
	
     Quest’operazione	
   avviene	
   attraverso	
   l'invio	
   del	
   messaggio	
   “alloc”:	
   alla	
   classe	
   dell'oggetto	
   sarà	
  
       restituita	
   un'istanza	
   grezza,	
   ovvero	
   non	
   inizializzata	
   di	
   quella	
   classe,	
   con	
   l'utilizzo	
   della	
   memoria	
  
       interna	
  destinata	
  al	
  programma.	
  
	
     Oltre	
  a	
  quest’operazione,	
  si:	
  
	
  
             ⇒ Configurerà	
  il	
  contatore	
  retain	
  a	
  1.	
  
             ⇒ S’inizializzerà	
  il	
  puntatore	
  all'oggetto	
  indicandogli	
  la	
  classe	
  dell'oggetto	
  stesso.	
  
             ⇒ S’inizializzerà	
  a	
  zero	
  o	
  a	
  valori	
  “nil”	
  tutte	
  le	
  variabili	
  della	
  classe.	
  
       	
  
       Essendo	
   il	
   puntatore	
   dell'oggetto	
   (chiamato	
   anche	
   “isa”)	
   ereditato	
   da	
   NSObject,	
   è	
   comune	
   a	
   tutti	
   gli	
  
       oggetti	
   Cocoa;	
   viene	
   configurato	
   alla	
   classe	
   dell’oggetto	
   da	
   inizializzare,	
   solo	
   dopo	
   aver	
   allocato	
   la	
  
       memoria	
  da	
  lasciare	
  all’oggetto	
  stesso.	
  E’	
  integrato	
  nella	
  vista	
  runtime	
  della	
  gerarchia	
  dell'ereditarietà	
  
       delle	
  classi	
  e	
  nella	
  rete	
  di	
  oggetti	
  che	
  costituiscono	
  il	
  programma.	
  
       Tutto	
   questo	
   procedimento	
   porterà	
   all’agevolazione	
   della	
   ricerca	
   delle	
   informazioni	
   al	
   tempo	
  
       d’esecuzione	
  del	
  programma.	
  
       Si	
  può	
  dire	
  che	
  l'allocazione	
  di	
  un	
  oggetto	
  in	
  memoria	
  consta	
  oltre	
  alla	
  predestinazione	
  di	
  una	
  parte	
  
       della	
  memoria	
  stessa	
  alla	
  variabile,	
  anche	
  di	
  due	
  inizializzazioni	
  riguardanti	
  il	
  contatore	
  “retain”	
  e	
  la	
  
       variabile	
  di	
  tipo	
  puntatore	
  “isa”,	
  non	
  rendendo	
  ancora	
  di	
  fatto	
  usabile	
  l'oggetto.	
  
       	
  

       2.3.7.1.2 	
   	
  Inizializzazione	
  
       Quest’operazione	
  ha	
  come	
  scopo	
  quello	
  di	
  impostare	
  le	
  variabili	
  d’istanza	
  di	
  un	
  oggetto	
  a	
  valori	
  iniziali	
  
       coerenti	
   con	
   le	
   variabili	
   stesse,	
   potendo	
   inoltre	
   allocare	
   e	
   disporre	
   altre	
   risorse	
   globali	
   di	
   cui	
   l'oggetto	
  
       deve	
   disporre	
   durante	
   il	
   suo	
   funzionamento.	
   Una	
   particolare	
   osservazione	
   va	
   fatta	
   a	
   riguardo	
   di	
  
       quest’operazione,	
   ossia	
   che	
   ogni	
   oggetto	
   presente	
   nel	
   programma,	
   dovrebbe	
   essere	
   inizializzato	
  
       tramite	
   un	
   suo	
   metodo	
   d’inizializzazione,	
   purché	
   non	
   sia	
   soltanto	
   necessaria	
   l'inizializzazione	
   di	
  
       default.	
  Nel	
  caso	
  in	
  cui,	
  non	
  si	
  preveda	
  un'inizializzazione	
  “personalizzata”	
  per	
  un	
  determinato	
  oggetto	
  
       e	
   Cocoa	
   lo	
   andrà	
   a	
   inizializzare	
   con	
   il	
   metodo	
   d’inizializzazione	
   più	
   vicino	
   gerarchicamente	
   all'oggetto	
  
       stesso.	
  
       	
  

       2.3.7.1.3 	
   Dealloc	
  
       Nelle	
  classi	
  Cocoa	
  che	
  usano	
  una	
  gestione	
  tradizionale	
  della	
  memoria,	
  il	
  metodo	
  usato	
  per	
  liberare	
  le	
  
       risorse	
   è	
   il	
   “dealloc”:	
   da	
   molti	
   punti	
   di	
   vista	
   questo	
   metodo	
   può	
   essere	
   considerato	
   come	
   la	
  
       controparte	
  del	
  metodo	
  init	
  della	
  classe.	
  
       Esso	
   è	
   invocato	
   proprio	
   prima	
   della	
   distruzione	
   dell'oggetto,	
   garantendo	
   che	
   le	
   istanze	
   dell'oggetto	
  
       vengano	
  rilasciate	
  e	
  che	
  la	
  memoria	
  allocata	
  dinamicamente	
  venga	
  liberata.	
  
       I	
   metodi	
   init	
   e	
   dealloc	
   possono	
   essere,	
   di	
   fatto,	
   considerati	
   complementari	
   in	
   quanto,	
   il	
   primo	
   invoca	
   il	
  
       designato	
  della	
  super	
  classe	
  al	
  primo	
  passo,	
  mentre	
  dealloc	
  invoca	
  il	
  suo	
  omologo	
  della	
  super	
  classe	
  
       solo	
  alla	
  fine.	
  




             	
                                                                                                                                                                  2-­‐20	
  
2.3.8 	
           Introspection	
  
E'	
   una	
   caratteristica	
   molto	
   potente	
   degli	
   ambienti	
   e	
   linguaggi	
   orientati	
   a	
   oggetti;	
   in	
   pratica	
   ci	
   si	
  
riferisce	
  alla	
  capacità	
  di	
  un	
  oggetto	
  di	
  divulgare	
  le	
  sue	
  informazioni	
  nella	
  fase	
  di	
  runtime.	
  	
  
Tali	
   dettagli	
   riguardano	
   il	
   posto	
   nella	
   catena	
   gerarchica,	
   la	
   conformità	
   a	
   determinati	
   protocolli	
   e	
   le	
  
risposte	
   a	
   determinati	
   messaggi.	
   Il	
   protocollo	
   e	
   la	
   classe	
   NSObject	
   definiscono	
   molti	
   metodi	
  
introspection	
  che	
  si	
  possono	
  usare	
  a	
  runtime	
  per	
  caratterizzare	
  gli	
  oggetti,	
  permettendo	
  di	
  acquisire	
  
familiarità	
  con	
  la	
  classe	
  dell’oggetto	
  e	
  di	
  conoscere	
  ad	
  esempio	
  quali	
  messaggi	
  inviare	
  oppure	
  non	
  a	
  un	
  
determinato	
  oggetto.	
  
Il	
   protocollo	
   NSObject	
   fornisce	
   diversi	
   metodi	
   per	
   determinare	
   la	
   posizione	
   di	
   un	
   oggetto	
   nella	
  
gerarchia	
  delle	
  classi	
  operando	
  su	
  diversi	
  livelli	
  di	
  granularità.	
  	
  
I	
  metodi	
  d’istanza	
  delle	
  classi	
  e	
  superclassi	
  per	
  esempio,	
  restituiscono	
  oggetti	
  Class	
  che	
  rappresentano	
  
rispettivamente	
   la	
   classe	
   e	
   la	
   superclasse	
   per	
   il	
   ricevitore:	
   essi	
   richiedono	
   di	
   confrontare	
   un	
   oggetto	
  
Class	
  con	
  un	
  altro	
  o	
  per	
  ottenere	
  un	
  ricevitore	
  appropriato	
  da	
  una	
  classe	
  di	
  messaggi.	
  
I	
   messaggi	
   invece	
   isKindOfClass:	
   oppure	
   isMemberOfClass:	
   permettono	
   di	
   verificare	
   la	
   classe	
   di	
  
appartenenza	
  di	
  un	
  oggetto	
  portando	
  ai	
  seguenti	
  risultati:	
  
	
  
        • Il	
  primo	
  restituisce	
  una	
  conferma	
  o	
  meno	
  se	
  il	
  ricevitore	
  è	
  un'istanza	
  di	
  una	
  determinata	
  classe	
  
               o	
  di	
  una	
  classe	
  da	
  essa	
  derivata.	
  	
  
        • Un	
  messaggio	
  isMemberOfClass:	
  d'altro	
  canto,	
  restituisce	
  conferma	
  se	
  il	
  ricevitore	
  è	
  un'istanza	
  
               di	
  una	
  specifica	
  classe.	
  
	
  

Il	
  messaggio	
  più	
  usato	
  è	
  il	
  “isKindOfClass”	
  poiché	
  da	
  esso	
  è	
  possibile	
  ricavare	
  in	
  un	
  solo	
  passaggio	
  la	
  
gamma	
  completa	
  di	
  messaggi	
  da	
  poter	
  inviare	
  a	
  un	
  oggetto.	
  	
  

if ([item isKindOfClass:[NSData class]]) {
const unsigned char *bytes = [item bytes];
unsigned int length = [item length];
// ...}
	
  
Tabella	
  2:	
  Esempio	
  di	
  codice	
  con	
  isKindOfClass	
  

Sapendo	
  che	
  l'oggetto	
  item	
  deriva	
  dalla	
  classe	
  NSData,	
  il	
  codice	
  successivo	
  sa	
  di	
  poter	
  inviare	
  lenght	
  
byte	
  e	
  il	
  messaggio	
  NSData.	
  	
  
La	
   differenza	
   tra	
   isKindOfClass:	
   e	
   isMemberOfClass:	
   diventa	
   evidente	
   se	
   si	
   assume	
   che	
   item	
   è	
  
un'istanza	
  di	
  NSMutableData.	
  
Se	
  si	
  usa	
  isMemberOfClass:	
  al	
  posto	
  diisKindOfClass:,	
  il	
  codice	
  nel	
  blocco	
  non	
  sarà	
  mai	
  eseguito	
  perché	
  
item	
  non	
  è	
  un'istanza	
  di	
  NSData	
  ma	
  di	
  NSMutableData,	
  una	
  sua	
  sottoclasse.	
  
	
  

2.3.9 	
           Oggetti	
  modificabili	
  
Gli	
  oggetti	
  Cocoa	
  possono	
  essere	
  raggruppati	
  in	
  due	
  insiemi	
  secondo	
  la	
  loro	
  modificabilità:	
  
	
  
        ⇒ mutabili	
  
        ⇒ immutabili	
  
	
  
I	
   due	
   si	
   differenziano	
   perché	
   nell'insieme	
   dei	
   “mutabili”	
   gli	
   oggetti	
   quando	
   sono	
  creati	
   possono	
   subire	
  
delle	
  modifiche	
  nel	
  loro	
  valore,	
  mentre	
  nei	
  secondi,	
  essi	
  dopo	
  l'inizializzazione	
  rimangono	
  gli	
  stessi.	
  
Le	
  impostazioni	
  predefinite	
  degli	
  oggetti	
  prevedono	
  che	
  essi	
  siano	
  mutabili.	
  
Il	
  frame	
  work	
  Foundation,	
  aggiunge	
  altre	
  caratteristiche	
  introducendo	
  il	
  concetto	
  di	
  classi	
  che	
  hanno	
  
varianti	
  mutabili	
  e	
  non,	
  come	
  nel	
  caso	
  delle	
  classi	
  NSMutableArray,	
  NSMutableString,	
  etc...	
  
La	
   necessità	
   di	
   rendere	
   un	
   oggetto	
   immutabile	
   risiede	
   nel	
   fatto	
   che	
   alcune	
   volte,	
   trattando	
   oggetti	
  
mutabili	
   ci	
   potrebbero	
   essere	
   problemi	
   di	
   coerenza	
   dei	
   dati,	
   poiché	
   una	
   variabile	
   potrebbe	
  
inaspettatamente	
  cambiare	
  valore	
  mentre	
  è	
  usata,	
  oppure	
  per	
  un	
  incremento	
  delle	
  prestazioni	
  poiché	
  

       	
                                                                                                                                                  2-­‐21	
  
se	
   un	
   oggetto	
   è	
   mutabile,	
   avrà	
   anche	
   dei	
   controlli	
   nella	
   gestione	
   della	
   quantità	
   di	
   memoria	
   da	
   allocare	
  
e	
  deallocare	
  che	
  rallenteranno	
  il	
  programma.	
  
La	
  politica	
  da	
  adottare	
  sulla	
  scelta	
  se	
  implementare	
  o	
  no,	
  variabili	
  mutabili,	
  è	
  esplicata	
  qui	
  di	
  seguito,	
  
in	
  maniera	
  molto	
  sintetica:	
  
	
  
        • Utilizzare	
  varianti	
  mutabili	
  di	
  oggetti	
  quando	
  richiedono	
  frequenti	
  modifiche.	
  	
  
        • E’	
  consigliabile	
  sostituire	
  un	
  oggetto	
  immutabile	
  piuttosto	
  che	
  gestirne	
  uno	
  mutabile	
  se	
  questo	
  
               non	
  richiede	
  modifiche	
  frequenti.	
  
	
  

2.3.10 	
           Raggruppamenti	
  di	
  classi	
  
Il	
   raggruppamento	
   di	
   classi	
   (detta	
   anche	
   Class	
   cluster)	
   è	
   uno	
   strumento	
   che	
   estende	
   l'uso	
   del	
   frame	
  
work	
  Foundation.	
  	
  
Lo	
  scopo	
  che	
  persegue	
  è	
  di	
  raggruppare	
  un	
  certo	
  numero	
  di	
  sottoclassi,	
  private	
  e	
  concrete	
  sotto	
  una	
  
super	
  classe	
  pubblica	
  e	
  astratta	
  con	
  lo	
  scopo	
  di	
  semplificare	
  l'architettura	
  pubblica	
  visibile	
  di	
  un	
  frame	
  
work	
  orientato	
  agli	
  oggetti	
  senza	
  ridurne	
  le	
  potenzialità.	
  
La	
   super	
   classe	
   astratta	
   deve	
   dichiarare	
   metodi	
   per	
   creare	
   istanze	
   delle	
   sue	
   sottoclassi	
   private,	
   ed	
  
inoltre,	
  è	
  responsabilità	
  della	
  super	
  classe	
  dispensare	
  un	
  oggetto	
  della	
  propria	
  sottoclasse	
  basato	
  su	
  un	
  
metodo	
  invocato.	
  Non	
  è	
  possibile	
  e	
  non	
  si	
  deve,	
  scegliere	
  la	
  classe	
  dell'istanza.	
  
È	
   anche	
   spesso	
   utile,	
   avere	
   due	
   o	
   più	
   classi	
   astratte	
   pubbliche	
   che	
   dichiarino	
   l'interfaccia	
   del	
  
raggruppamento.	
  	
  
Questo	
  è	
  evidente	
  nel	
  Framework	
  Foundation	
  che	
  include	
  questi	
  raggruppamenti:	
  
         • NSData	
  diviso	
  in	
  NSData	
  e	
  NSMutableData;	
  
         • NSArray	
  diviso	
  in	
  NSArray	
  e	
  NSMutableArray;	
  
         • NSString	
  diviso	
  in	
  NSArray	
  ed	
  NSMutableString;	
  
         • NSDictionary	
  diviso	
  in	
  NSDictionary	
  e	
  NSMutableDictionary.	
  




3 PROGETTAZIONE	
  
	
  
In	
   questo	
   capitolo	
   è	
   analizzata	
   la	
   progettazione	
   di	
   tutto	
   il	
   sistema:	
   il	
   lavoro	
   per	
   essere	
   sviluppato	
   in	
  
maniera	
   più	
   semplice	
   è	
   stato	
   suddiviso	
   in	
   più	
   moduli,	
   ciascuno	
   dei	
   quali	
   focalizza	
   le	
   singole	
  
problematiche	
  e	
  cerca	
  di	
  risolverle	
  in	
  maniera	
  da	
  agevolare	
  lo	
  sviluppo	
  del	
  lavoro	
  complessivo	
  come	
  
raffigurato	
  nel	
  seguente	
  grafico:	
  
	
  
	
  




       	
                                                                                                                                                         3-­‐22	
  
Dexinizione	
  dell'obiettivo	
  




                                                       Analisi	
  dei	
  problemi	
  generici	
  
                                                  (implementazione	
  dei	
  sensori	
  e	
  delle	
  
                                                 periferiche	
  del	
  dispositivo	
  nel	
  progetto)	
  




                                                     Analisi	
  delle	
  singole	
  problematiche	
  




                                                    Implementazione	
  del	
  prodotto	
  xinale	
  
                                                                                                                                                                           	
  
3.1 Definizione	
  dell’obiettivo	
  
Il	
   programma	
   che	
   ha	
   come	
   oggetto	
   la	
   tesi	
   è	
   la	
   creazione	
   di	
   un	
   sistema	
   implementato	
   su	
   Iphone	
   che	
  
riesca	
  tramite	
  l'obiettivo	
  della	
  macchina	
  fotografica	
  a	
  riconoscere	
  dei	
  POI	
  (punti	
  d’interesse)	
  inseriti	
  
dall'utente	
  nella	
  memoria	
  del	
  dispositivo	
  oppure	
  scaricati	
  da	
  web,	
  localizzati	
  nelle	
  sue	
  vicinanze,	
  che	
  li	
  
visualizzi	
  su	
  una	
  mappa	
  e	
  che	
  infine	
  fornisca	
  all’utente	
  le	
  funzioni	
  semplificate	
  di	
  un	
  navigatore.	
  
	
  

3.2 Analisi	
  dei	
  problemi	
  generici	
  	
  
Prima	
  dello	
  sviluppo	
  del	
  codice	
  necessario	
  al	
  programma,	
  si	
  è	
  dovuto	
  attuare	
  uno	
  studio	
  generico	
  sui	
  
sensori	
   e	
   periferiche	
   già	
   integrati	
   sull'Iphone	
   decidendo	
   quindi	
   il	
   modello	
   sul	
   quale	
   avviare	
   la	
  
progettazione,	
   in	
   modo	
   da	
   essere	
   compatibili	
   con	
   l'obiettivo	
   iniziale;	
   poiché	
   non	
   tutte	
   le	
   versioni	
  
presenti	
  sul	
  mercato	
  in	
  questo	
  momento	
  hanno	
  le	
  periferiche	
  integrate	
  richieste.	
  
Una	
   volta	
   imposto	
   il	
   modello,	
   si	
   sono	
   analizzati	
   i	
   problemi	
   riguardanti	
   la	
   gestione	
   e	
   l'implementazione	
  
delle	
  librerie	
  nel	
  progetto	
  con	
  la	
  documentazione	
  presente	
  sul	
  sito	
  internet	
  della	
  Apple,	
  con	
  lo	
  scopo	
  di	
  
apprendere	
  le	
  nozioni	
  riguardanti	
  il	
  funzionamento	
  teorico	
  e	
  pratico	
  delle	
  librerie	
  per	
  la	
  gestione	
  del	
  
ricevitore	
  GPS,	
  della	
  foto	
  camera,	
  dell’accelerometro	
  e	
  del	
  magnetometro,	
  quest’ultimo	
  presente	
  solo	
  	
  
nella	
  versione	
  dell’Iphone	
  3GS.	
  
	
  

3.3 Scomposizione	
  delle	
  singole	
  problematiche	
  
I	
  problemi	
  iniziali	
  su	
  cui	
  si	
  è	
  posta	
  maggiore	
  attenzione	
  sono	
  stati	
  i	
  seguenti:	
  

         ⇒ La	
  gestione	
  della	
  macchina	
  fotografica	
  integrata	
  e	
  della	
  memorizzazione	
  di	
  eventuali	
  foto	
  
           scattate	
  dall'utente.	
  
         ⇒ La	
  gestione	
  del	
  ricevitore	
  GPS,	
  del	
  magnetometro	
  e	
  dell’accelerometro.	
  	
  
         ⇒ L'associazione	
  di	
  informazioni	
  aggiuntive	
  alle	
  foto	
  scattate	
  come	
  ad	
  esempio	
  la	
  latitudine,	
  la	
  
           longitudine	
  ed	
  un	
  campo	
  descrittivo	
  di	
  ogni	
  singolo	
  scatto.	
  
         ⇒ La	
  visualizzazione	
  degli	
  eventuali	
  punti	
  d’interesse	
  memorizzati,	
  sull'obiettivo	
  della	
  fotocamera.	
  

      	
                                                                                                                                                      3-­‐23	
  
⇒ L'eventuale	
  iterazione	
  del	
  dispositivo	
  con	
  un	
  web	
  service	
  per	
  permettere	
  all'utente	
  di	
  
            visualizzare	
  a	
  suo	
  piacimento	
  i	
  POI	
  (punti	
  d’interesse)	
  posti	
  attorno	
  alla	
  sua	
  posizione.	
  
          ⇒ La	
  localizzazione	
  sulla	
  mappa	
  dei	
  punti	
  d’interesse.	
  
          ⇒ La	
  memorizzazione	
  dei	
  dati.	
  
          ⇒ L’uso	
  dei	
  dati	
  provenienti	
  da	
  un	
  web-­service.	
  
          ⇒ Il	
  frame	
  work	
  MapKit.	
  
          ⇒ La	
  libreria	
  dell’Augmented	
  Reality(AR).	
  

	
  

	
  




Figura	
  4:	
  Progetto	
  finale                                                                                                                	
  

	
  

3.3.1 Gestione	
  del	
  frame	
  work	
  CoreLocation	
  
La	
  classe	
  principale	
  del	
  CoreLocation	
  è	
  la	
  CLLocationManager	
  che	
  rappresenta	
  l’entry	
  point	
  per	
  tutte	
  le	
  
applicazioni	
   che	
   vogliono	
   interagire	
   con	
   il	
   ricevitore	
   GPS	
   per	
   ottenere	
   la	
   sua	
   posizione	
   corrente	
   in	
  
coordinate	
  espresse	
  in	
  latitudine	
  e	
  longitudine.	
  
I	
  passi	
  da	
  seguire	
  per	
  ricavare	
  queste	
  informazioni	
  sono	
  i	
  seguenti:	
  
               ⇒ La	
  creazione	
  di	
  un'istanza	
  della	
  classe	
  CLLocationManager	
  se	
  non	
  esiste	
  già;	
  
               ⇒ La	
  sua	
  configurazione	
  attraverso	
  il	
  settaggio	
  dei	
  suoi	
  parametri.	
  
               ⇒ L’invocazione	
  del	
  metodo	
  startUpdatingLocation	
  per	
  iniziare	
  la	
  localizzazione	
  dell’utente.	
  
               ⇒ L’invocazione	
  dello	
  stopUpdatingLocation	
  per	
  lo	
  stop	
  della	
  localizzazione.	
  
	
  

Nel	
  secondo	
  passaggio	
  i	
  parametri	
  da	
  impostare	
  saranno	
  i	
  seguenti:	
  
          1. desideredAccuracy.:	
   imposta	
   una	
   determinata	
   precisione	
   nella	
   misurazione(in	
   termini	
   di	
  
             metri).	
  
             	
  
             Per	
  questa	
  configurazione	
  posso	
  ricorrere	
  ai	
  seguenti	
  parametri:	
  
                              o kCLLocationAccuracyBest.	
  Specifica	
  la	
  migliore	
  precisione	
  di	
  default.	
  	
  
                              o kCLLocationAccuracyNearestTenMeters.	
  Impone	
  una	
  precisione	
  di	
  10	
  metri.	
  
                              o kCLLocationAccuracyHundredMeter.	
  Impone	
  una	
  precisione	
  di	
  100	
  metri.	
  
                              o kCLLocationAccuracyKilometer.	
  Accuratezza	
  di	
  1000	
  metri.	
  

       	
                                                                                                                                                3-­‐24	
  
o kCLLocationAccuracyThreeKilometers.	
   Rappresenta	
   una	
   precisione	
   di	
   3000	
  
                                     metri.	
  
          2. distanceFilter.:il	
   valore	
   di	
   questa	
   proprietà	
   determina	
   quanto	
   spesso	
   viene	
   eseguito	
   un	
  
             aggiornamento	
   sul	
   posizionamento,	
   in	
   termini	
   di	
   distanza	
   percorsa	
   dall'utente.	
   Tutti	
   i	
   valori	
  
             qui	
  riferiti	
  sono	
  espressi	
  in	
  metri.	
  	
  
          3. delegate.:questa	
   proprietà	
   specifica	
   il	
   delegate	
   che	
   riceve	
   gli	
   aggiornamenti	
   ovvero	
   la	
   classe	
  
             scritta	
   dallo	
   sviluppatore	
   che	
   implementa	
   il	
   protocollo	
   CLLocationManagerDelegate.	
   Esso	
   è	
  
             dotato	
  di	
  due	
  metodi	
  non	
  obbligatori:	
  

                     o          locationManager:didUpdateToLocation:fromLocation:.	
  
                     o          locationManager:didFailWithError:.	
  
	
  
                         Il	
   primo	
   è	
   un	
   metodo	
   invocato	
   quando	
   il	
   location	
   manager	
   vuole	
   aggiornare	
   la	
  
                         posizione	
  del	
  dispositivo.	
  	
  
                         Riceve	
  come	
  primo	
  riferimento,	
  un	
  riferimento	
  al	
  location	
  manager,	
  mentre	
  il	
  secondo	
  
                         parametro	
  è	
  un'istanza	
  della	
  classe	
  CLLocation	
  che	
  ingloba	
  la	
  nuova	
  posizione.	
  
                         Il	
   secondo	
   metodo	
   invece	
   è	
   invocato	
   solo	
   in	
   caso	
   di	
   errore	
   (ad	
   esempio	
   quando	
   non	
   sia	
  
                         attivo	
  il	
  ricevitore	
  GPS	
  integrato).	
  	
  
                         Non	
   bisogna	
   inoltre	
   dimenticare	
   di	
   implementare	
   all'interno	
   del	
   codice	
   il	
   protocollo	
  
                         CLLocationManagerDelegate	
   e	
   assegnare	
   l'istanza	
   di	
   questa	
   classe	
   alla	
   proprietà	
  
                         delegate	
  dell'istanza	
  del	
  CLLocationManager.	
  

                         	
  

3.3.1.1 La	
  classe	
  CLLocation	
  
La	
  latitudine	
  e	
  la	
  longitudine	
  sono	
  dei	
  dati	
  espressi	
  in	
  gradi	
  che	
  definiscono	
  una	
  “griglia”	
  virtuale	
  per	
  il	
  
globo	
   terrestre	
   con	
   lo	
   scopo	
   di	
   creare	
   un	
   sistema	
   di	
   riferimento	
   per	
   l'individuazione	
   di	
   un	
   generico	
  
punto	
  sulla	
  Terra.	
  	
  
Il	
   sistema	
   di	
   rilevamento	
   adottato	
   è	
   il	
   GPS	
   che	
   utilizza	
   come	
   coordinate	
   di	
   riferimento	
   l'ellissoide	
  
WGS84	
  e	
  avrà	
  per	
  la	
  latitudine	
  un	
  intervallo	
  che	
  andrà	
  da	
  -­‐90°	
  a	
  +90°,	
  rispettivamente	
  per	
  il	
  Polo	
  Sud	
  e	
  
il	
  Polo	
  Nord,	
  mentre	
  in	
  longitudine	
  si	
  avrà	
  un	
  intervallo	
  compreso	
  tra	
  -­‐180°	
  e	
  +180°.	
  
La	
   classe	
   CLLocation	
   incapsulerà	
   i	
   dati	
   della	
   posizione	
   generica	
   di	
   un	
   utente,	
   generati	
   da	
   un	
   oggetto	
  
CLLocationManager	
  e	
  li	
  memorizzerà	
  all'interno	
  delle	
  seguenti	
  proprietà:	
  	
  
         ⇒ coordinate:	
  conterrà	
  la	
  latitudine	
  e	
  la	
  longitudine	
  del	
  dispositivo	
  in	
  gradi.	
  	
  
         ⇒ altitude.:	
   restituisce	
   l'altezza	
   del	
   dispositivo	
   in	
   metri.	
   I	
   valori	
   positivi	
   indicano	
   l'altezza	
   sopra	
   il	
  
               livello	
  del	
  mare	
  mentre	
  quelli	
  negativi	
  indicano	
  un'altezza	
  sotto	
  il	
  livello	
  del	
  mare.	
  
         ⇒ horizontalAccuracy	
   &	
   verticalAccuracy.:	
   entrambe	
   restituiscono	
   delle	
   precisioni	
   delle	
   misure	
  
               effettuate	
  riguardo,	
  la	
  prima	
  le	
  coordinate	
  piane	
  mentre	
  la	
  seconda	
  l’altezza.	
  
         ⇒ timestamp.:	
  corrisponde	
  all'epoca	
  in	
  termini	
  temporali	
  di	
  quando	
  è	
  stata	
  eseguita	
  la	
  misura.	
  
	
  

Nella	
   maggior	
   parte	
   dei	
   casi,	
   gli	
   oggetti	
   di	
   tipo	
   CLLocation	
   sono	
   ricevuti	
   dal	
   location	
   manager,	
   ma	
   si	
  
potrebbe	
  comunque	
  inizializzare	
  in	
  maniera	
  indipendente	
  quest'oggetto	
  con	
  i	
  seguenti	
  due	
  metodi:	
  

       ⇒ initWithLatitude:longitude:	
  
       ⇒ initWithCoordinate:altitude:horizontalAccuracy:	
  verticalAccuracy:timestamp:.	
  
	
  
Esiste	
   un	
   ultimo	
   metodo,	
   presente	
   nella	
   classe,	
   che	
   è	
   utilizzato	
   per	
   calcolare	
   la	
   distanza	
   percorsa	
  
dall'utente	
  ed	
  è	
  chiamato	
  getDistanceFrom:.	
  
	
  
@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) CLLocation *newCenter;	
  
- (void)locationManager:(CLLocationManager *)manager
     didUpdateToLocation:(CLLocation *)newLocation

       	
                                                                                                                                                           3-­‐25	
  
fromLocation:(CLLocation *)oldLocation {
      newCenter = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude
longitude:newLocation.coordinate.longitude];

}	
  
Codice	
  2:	
  implementazione	
  della	
  classe	
  CLLocation	
  

3.3.1.2 La	
  classe	
  CLHeading	
  	
  
La	
   versione	
   più	
   recente	
   del	
   dispositivo	
   (l'Iphone	
   3GS)	
   dispone	
   di	
   un	
   magnetometro	
   che	
   permette	
   di	
  
restituire	
  i	
  valori	
  del	
  Nord	
  magnetico	
  del	
  campo	
  terrestre,	
  espressi	
  attraverso	
  gradi	
  centesimali	
  .	
  
Essa	
   è	
   sempre	
   gestita,	
   come	
   nel	
   caso	
   del	
   GPS,	
   dal	
   frame	
   work	
   CoreLocation	
   e	
   in	
   particolare	
   dal	
  
CLLocationManager.	
  
Le	
   chiamate	
   dedicate	
   alla	
   gestione	
   del	
   magnetometro	
   restituiscono	
   oggetti	
   di	
   tipo	
   CLHeading	
   che	
  
avranno	
  le	
  seguenti	
  proprietà:	
  
	
  
                    ⇒ magneticHeading	
  	
  
                    ⇒ trueHeading	
  	
  
                    ⇒ headingAccuracy	
  
                    ⇒ timestamp	
  
	
  

La	
  prima	
  restituirà	
  il	
  polo	
  nord	
  magnetico	
  che	
  corrisponderà	
  al	
  campo	
  magnetico	
  della	
  Terra,	
  mentre	
  
la	
   seconda	
   conterrà	
   il	
   valore	
   corrispondente	
   al	
   polo	
   geografico.	
   La	
   terza	
   proprietà	
   conterrà	
   la	
  
precisione	
  della	
  misura	
  e	
  la	
  quarta	
  invece	
  il	
  periodo	
  in	
  cui	
  è	
  stata	
  compiuta	
  la	
  misura.	
  

@property (nonatomic, retain) CLLocationManager *locationManager;
…
self.locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
…
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:
(CLHeading *)newHeading
{
// rotazione in radianti

float rotation = newHeading.trueHeading * M_PI / 180;
...
}
	
  
Codice	
  3:	
  implementazione	
  della	
  classe	
  CLHeading	
  




        	
                                                                                                                                               3-­‐26	
  
3.3.2 Gestione	
  dell’UIAccelerometer	
  
	
  




                                                                  	
  
Figura	
  5:	
  Assi	
  corrispondenti	
  all'accelerometro	
  

E'	
  necessario	
  come	
  prima	
  cosa,	
  considerare	
  l'accelerometro	
  installato	
  all'interno	
  del	
  dispositivo	
  come	
  
un	
  aiuto	
  per	
  la	
  costruzione	
  delle	
  interfacce	
  grafiche	
  poiché	
  grazie	
  a	
  questo	
  elemento,	
  l'utente	
  riesce	
  a	
  
visualizzare	
   in	
   maniera	
   corretta	
   l'interfaccia	
   grafica	
   adattandola	
   alle	
   condizioni	
   fisiche	
   esterne	
   come	
  
ad	
   esempio	
   nel	
   caso	
   della	
   rotazione	
   dell'Iphone.	
   Implementando	
   al	
   suo	
   interno	
   le	
   funzioni	
  
dell'accelerometro	
  si	
  potrà	
  far	
  ruotare	
  la	
  schermata	
  nel	
  senso	
  d’inclinazione	
  dello	
  schermo.	
  
	
  
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrienta
tion {
      // Return YES for supported orientations
      return (interfaceOrientation == UIInterfaceOrientationPortrait);
}	
  
	
  
Questa	
   funzione	
   che	
   permette	
   di	
   ottenere	
   questo	
   risultato	
   è	
   implementata	
   nella	
   forma	
   standard	
   del	
  
codice,	
  cosicché	
  il	
  programmatore	
  non	
  sarà	
  obbligato	
  a	
  implementarla	
  autonomamente	
  durante	
  ogni	
  
creazione	
  delle	
  interfacce	
  grafiche.	
  
Qualora	
   però	
   si	
   volessero	
   utilizzare	
   i	
   dati	
   dell’accelerometro	
   nel	
   progetto,	
   si	
   dovrà	
   aggiungere	
  
all’header	
   del	
   suo	
   UIViewController,	
   il	
   protocollo	
   UIAccelerometerDelegate	
   dichiarando	
   poi	
   nello	
  
sviluppo	
   della	
   classe,	
   il	
   metodo	
   accelerometer:didAccelerate	
   	
   che	
   ritornerà	
   i	
   dati	
   riguardanti	
   lo	
  
spostamento	
  sugli	
  assi(x,y,z)	
  espressi	
  in	
  valori	
  di	
  tipo	
  floating	
  point.	
  
	
  
	
  
	
  
@interface AccelController : UIViewController <UIAccelerometerDelegate> {
UIAccelerometer *accelerometer;
}	
  
…
accelerometer = [UIAccelerometer sharedAccelerometer];
accelerometer.updateInterval = 0.1;

accelerometer.delegate                    =
     	
                                                                                                                                         3-­‐27	
  
…
(void)accelerometer:(UIAccelerometer *)meter
didAccelerate:(UIAcceleration *)acceleration {
float x = acceleration.x;
float y = acceleration.y;
float z = acceleration.z;
float angle = atan2(y, x);
 self;	
  
Codice	
  4:	
  Implementazione	
  dell’UIAccelerometer	
  

3.3.3 Gestione	
  della	
  fotocamera	
  
La	
   gestione	
   diretta	
   dell’obiettivo	
   integrato	
   nell’Iphone	
   e	
   della	
   sua	
   libreria	
   fotografica,	
   è	
   delegata	
   al	
  
controller	
  UIImagePickerController,	
  che	
  abilita	
  la	
  selezione	
  e	
  la	
  modifica	
  di	
  una	
  generica	
  foto.	
  
Lo	
  sviluppatore,	
  per	
  poterlo	
  utilizzare,	
  determina	
  prima	
  il	
  tipo	
  di	
  sorgente	
  da	
  adoperare	
  e	
  poi	
  il	
  suo	
  
delegate,	
   ovvero	
   la	
   classe	
   che	
   risponde	
   a	
   tutti	
   i	
   singoli	
   eventi	
   scatenati	
   dall'utente	
   quando	
   usa	
   la	
  
fotocamera	
  del	
  telefono.	
  
La	
  persona	
  che	
  sviluppa	
  programmi	
  in	
  Objective-­‐C	
  deve	
  tenere	
  in	
  considerazione	
  che	
  nel	
  simulatore	
  
usato	
  per	
  testare	
  il	
  programma,	
  come	
  anche	
  in	
  altri	
  dispositivi	
  Apple	
  presenti	
  sul	
  mercato	
  (ad	
  esempio	
  
l'Itouch),	
   la	
   fotocamera	
   non	
   è	
   implementata,	
   quindi	
   dovrà	
   ricorrere	
   ad	
   una	
   verifica	
   preventiva	
   sulla	
  
sua	
  presenza	
  attraverso	
  la	
  seguente	
  funzione:	
  	
  
	
  
+	
  (BOOL)isSourceTypeAvailable:(UIImagePickerControllerSourceType)	
  sourceType	
  
	
  
Essa	
   ritornerà	
   un	
   valore	
   booleano	
   corrispondente	
   al	
   “YES”	
   se	
   la	
   camera	
   sarà	
   nel	
   dispositivo	
   oppure	
  
“NO”	
  nel	
  caso	
  sia	
  assente.	
  
I	
  tipi	
  di	
  sorgente	
  validi	
  saranno	
  tre:	
  
                       I. UIImagePickerControllerSourceTypePhotoLibrary:per	
   la	
   selezione	
   delle	
   foto	
   dalla	
  
                            libreria	
  dell'Iphone;	
  
                       II. UIImagePickerControllerSourceTypeCamera:	
  per	
  la	
  selezione	
  delle	
  foto	
  dalla	
  camera;	
  
                       III. UIImagePickerControllerSourceTypeSavedPhotoAlbum:	
  per	
  la	
  selezione	
  delle	
  immagini	
  
                            dal	
  rullino	
  della	
  camera	
  o	
  dalla	
  libreria	
  se	
  il	
  dispositivo	
  non	
  è	
  provvisto	
  della	
  camera.	
  
	
  

Le	
  proprietà	
  dell’UIImagePickerController	
  da	
  impostare	
  saranno	
  due:	
  

              ⇒ delegate	
  
              ⇒ sourceType	
  

Il	
   delegate	
   è	
   stato	
   descritto	
   precedentemente,	
   mentre	
   per	
   quanto	
   riguarda	
   la	
   seconda	
   proprietà,	
   verrà	
  
configurata	
  utilizzando	
  uno	
  dei	
  tre	
  tipi	
  di	
  sorgente	
  appena	
  menzionati.	
  

	
  La	
   classe	
   che	
   sarà	
   delegata	
   dal	
   controller	
   (potrà	
   essere	
   essa	
   stessa	
   il	
   suo	
   delegate),	
   dovrà	
   essere	
  
sviluppata	
   seguendo	
   il	
   protocollo	
   UIImagePickerControllerDelegate	
   che	
   prevederà	
   l’implementazione	
  
di	
  due	
  metodi:	
  

       ⇒ -­(void)imagePickerController:(UIImagePickerController*)picker	
  
         didFinishPickingMediaWithInfo:(NSDictionary	
  *)info	
  	
  richiamato	
  quando	
  un	
  utente	
  selezionerà	
  
         una	
  foto	
  dalla	
  camera	
  o	
  un'immagine	
  dalla	
  libreria	
  fotografica;	
  
       ⇒ 	
  -­(void)imagePickerControllerDidCancel:(UIImagePickerController	
   *)picker	
   richiamato	
   quando	
  
         l'utente	
  invece	
  annullerà	
  la	
  selezione;	
  
	
  



       	
                                                                                                                                                    3-­‐28	
  
Il	
   primo	
   metodo	
   ha	
   come	
   parametri	
   in	
   ingresso	
   un	
   riferimento	
   all’image	
   picker	
   mentre	
   il	
   secondo	
  
parametro	
  sarà	
  di	
  tipo	
  dictionary	
  poiché	
  conterrà	
  le	
  informazioni	
  riguardanti	
  l’editing	
  della	
  foto.	
  

3.3.4 La	
  memorizzazione	
  dei	
  dati	
  
Il	
  sistema	
  scelto	
  nel	
  progetto	
  per	
  la	
  memorizzazione	
  dei	
  dati	
  in	
  maniera	
  persistente	
  è	
  stato	
  quello	
  del	
  
CoreData.	
  




                                                                                              Figura	
  6:	
  Struttura	
  del	
  CoreData	
  

Esso	
   è	
   un	
   sistema,	
   il	
   cui	
   rilascio	
   è	
   avvenuto	
   in	
   parallelo	
   alla	
   disponibilità	
   al	
   pubblico	
   del	
   sistema	
  
operativo	
   Iphone	
   OS	
   X	
   3.0	
   SDK.	
   Poiché	
   fin	
   da	
   subito	
   si	
   è	
   dimostrato,	
   essere	
   più	
   veloce,	
   robusto	
   e	
  
intuitivo	
   per	
   la	
   programmazione	
   rispetto	
   al	
   sistema	
   di	
   tabelle	
   SQLite	
   disponibili	
   nelle	
   versioni	
  
precedenti	
  del	
  sistema	
  operativo,	
  ha	
  avuto	
  una	
  rapida	
  diffusione	
  nell’implementazione	
  nei	
  programmi.	
  
I	
  vantaggi	
  riguardano	
  l’introduzione	
  di	
  un	
  sistema	
  per	
  la	
  visualizzazione	
   dei	
  modelli	
  dati	
  e	
  la	
  presenza	
  
di	
   un’infrastruttura	
   per	
   il	
   controllo	
   degli	
   oggetti	
   con	
   la	
   conseguente	
   separazione	
   della	
   gestione	
  
dell’oggetto	
  da	
  parte	
  del	
  codice.	
  

Questo	
  frame	
  work	
  consiste	
  di	
  tre	
  parti	
  importanti:	
  

          ⇒ managed	
  object	
  model	
  che	
  contiene	
  una	
  collezione	
  di	
  oggetti	
  e	
  delle	
  loro	
  relazioni	
  
          ⇒ managed	
  object	
  context	
  contiene	
  gli	
  oggetti	
  creati	
  dalle	
  entità	
  
          ⇒ data	
  store	
  raggruppa	
  tutti	
  gli	
  oggetti	
  creati	
  attraverso	
  il	
  managed	
  object	
  model.	
  

	
  

3.3.4.1 Il	
  modello	
  
Il	
  concetto	
  fondamentale	
  da	
  ricordare	
  è	
  che	
  un	
  modello	
  è	
  considerato	
  come	
  un	
  contenitore	
  delle	
  entità,	
  
e	
  le	
  entità	
  contengono	
  gli	
  attributi:	
  in	
  Xcode	
  esso	
  è	
  riconosciuto	
  nel	
  file	
  con	
  estensione	
  xcdatamodel	
  e	
  
tramite	
  il	
  corretto	
  editor	
  sarà	
  possibile	
  inserirvi	
  le	
  tabelle	
  e	
  stabilire	
  le	
  relazioni	
  tra	
  le	
  varie	
  entità.	
  

3.3.4.2 Le	
  entità	
  
Le	
   entità	
   nei	
   modelli	
   forniscono	
   per	
   le	
   librerie	
   “Core	
   Data	
   “	
   il	
   come”	
   istanziare	
   nuovi	
   oggetti	
   e	
  
memorizzarli.	
  
Esse	
   sono	
   rappresentate	
   tramite	
   la	
   classe	
   NSEntityDescription	
   e	
   descritte	
   tramite	
   le	
   istanze	
   di	
  
NSManagedObject	
  che	
  in	
  questo	
  sistema	
  rappresentano	
  i	
  dati	
  persistenti.	
  
	
  

3.3.4.3 Managed	
  object	
  model	
  
L'NSManagedObjectModel	
   contiene	
   le	
   entità	
   e	
   le	
   sue	
   relazioni	
   fungendo	
   da	
   schema	
   dell'applicazione	
  
attraverso	
  la	
  descrizione	
  delle	
  entità	
  usate	
  nel	
  “managed	
  object	
  context”.	
  
       	
                                                                                                                                                      3-­‐29	
  
La	
   via	
   più	
   semplice	
   per	
   ottenerlo	
   è	
   mediante	
   il	
   metodo	
   mergedModelFromBundles	
   che	
   crea	
   il	
  
managedObjectModel	
   attraverso	
   la	
   fusione	
   di	
   tutti	
   i	
   modelli,	
   come	
   mostrato	
   nel	
   seguente	
   pezzo	
   di	
  
codice:	
  
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles: nil] retain];
	
  
	
  

3.3.4.4 Managed	
  object	
  context	
  
Questa	
   classe	
   rappresenta	
   il	
   “contesto”	
   dell’applicazione	
   ovvero	
   il	
   punto	
   dove	
   vengono	
   aggiunte	
   le	
  
entità	
  all’applicazione.	
  Per	
  poterlo	
  ottenere	
  all’interno	
  di	
  un’applicazione,	
  si	
  dovrà:	
  

       ⇒ Allocare	
  e	
  inizializzare	
  una	
  nuova	
  istanza	
  della	
  classe	
  ManagedObjectContext	
  
       ⇒ Impostare	
  il	
  PersistentStoreCoordinator	
  

managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
	
  
	
  

3.3.4.4.1 NSManagedObject	
  
Analizzando	
   meglio	
   il	
   funzionamento	
   si	
   potrà	
   dire	
   che	
   l'NSManagedObjectContext	
   gestisce	
   le	
   istanze	
  
della	
  classe	
  NSManagedObject	
  che	
  sono	
  create	
  dalle	
  entità.	
  
L'applicazione	
   preleverà	
   i	
   dati	
   dal	
   persistent	
   store	
   usando	
   le	
   entità	
   nel	
   modello	
   per	
   creare	
  
l'NSManagedObject	
   situato	
   nel	
   contesto:	
   le	
   NSEntityDescription	
   saranno	
   considerate	
   come	
   classi	
   e	
  
l'NSManagedObject	
  come	
  oggetti.	
  
	
  

3.3.4.4.2 Fetching	
  entities	
  
I	
  managed	
  object	
  rimangono	
  nel	
  persistent	
  data	
  store	
  fino	
  a	
  quando	
  sono	
  necessari:	
  gli	
  oggetti	
  richiesti	
  
al	
  persist	
  data	
  store	
  sono	
  memorizzati	
  usando	
  la	
  classe	
  NSFetchRequest	
  che	
  ingloba	
  il	
  criterio	
  di	
  
ricerca	
  per	
  la	
  restituzione	
  di	
  determinati	
  dati	
  dal	
  persistent	
  data	
  store.	
  
Una	
  richiesta	
  di	
  questo	
  tipo	
  sarà	
  composta	
  di	
  un	
  NSEntityDescriptor	
  e	
  di	
  due	
  elementi	
  non	
  obbligatori:	
  
	
  
       ⇒ NSPredicate	
  
       ⇒ NSSortDescriptor	
  	
  

3.3.4.4.2.1 NSPredicate	
  
Questa	
   classe	
   pone	
   delle	
   restrizioni	
   nei	
   dati	
   restituiti	
   dall’NSFetchRequest:	
   potrebbe	
   essere	
  
paragonata	
  al	
  WHERE	
  nell'SQL.	
  

3.3.4.4.2.2 NSSortDescriptor	
  
Questa	
   classe	
   permetterà	
   di	
   restituire	
   una	
   collezione	
   di	
   dati	
   provenienti	
   dal	
   CoreData	
   secondo	
   un	
  
certo	
  criterio.	
  
	
  
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"namePhoto"
ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
	
  
	
  

3.3.4.4.3 NSFetchRequest	
  
E'	
   la	
   classe	
   utilizzata	
   per	
   eseguire	
   le	
   interrogazioni	
   al	
   sistema	
   di	
   tabelle	
   assieme	
   alla	
  
NSEntityDescription	
  che	
  è	
  usato	
  per	
  conoscere	
  quale	
  entità	
  si	
  analizza.	
  
       	
                                                                                                                                       3-­‐30	
  
Per	
  poterla	
  usare,	
  è	
  necessario	
  prima,	
  creare	
  due	
  istanze,	
  una	
  della	
  classe	
  NSEntityDescription	
  e	
  l’altra	
  
della	
  NSFecthRequest,	
  poi	
  è	
  necessario	
  associare	
  la	
  NSEntityDescription	
  alla	
  NSFetchRequest	
  ed	
  infine	
  
ci	
  sarà	
  la	
  NSManagedRequest	
  	
  che	
  eseguirà	
  la	
  richiesta.	
  
	
  
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Photo"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];

	
  


3.3.4.4.4 deleteObject	
  
Come	
   dice	
   il	
   nome	
   stesso	
   del	
   metodo,	
   si	
   trova	
   nella	
   classe	
   NSManagedObjectContext	
   e	
   serve	
   per	
   la	
  
cancellazione	
  degli	
  oggetti	
  dal	
  managed	
  Object	
  context	
  	
  dall’applicazione.	
  

NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
	
  
	
  

3.3.4.4.5 insertNewObjectForEntityForName	
  
Tutti	
  gli	
  oggetti	
  gestiti	
  da	
  un	
  managed	
  object	
  context	
  sono	
  istanze	
  della	
  classe	
  NSManagedObject	
  che	
   è	
  	
  
una	
  classe	
  che	
  implementa	
  il	
  “comportamento”	
  richiesto	
  per	
  un	
  modello	
  CoreData.	
  
Non	
  è	
  possibile	
  creare	
  istanze	
  di	
  NSManagedObject,	
  ma	
  solo	
  sottoclassi,	
  create	
  solitamente	
  dalle	
  entità	
  
(tabelle)	
  definite	
  nel	
  file	
  xcdatamodel.	
  
Il	
  codice	
  quindi	
  compirà	
  le	
  seguenti	
  azioni:	
  
        1. Creare	
  un	
  nuovo	
  ManagedObjectContext	
  basato	
  sull'entità;	
  
        2. Inserire	
  il	
  managed	
  object	
  context	
  corrente.
	
  

PhotoPoint *image = [NSEntityDescription
insertNewObjectForEntityForName:@"PhotoPoint"inManagedObjectContext:photo.managed
ObjectContext];
photo.photoPoint = image;
[image setValue:selectedImage forKey:@"photoPoint"];
	
  
	
  
Dopo	
  l'inserimento	
  sarà	
  possibile	
  eseguire	
  le	
  impostazioni	
  alle	
  sue	
  proprietà.
	
  

3.3.4.5 NSPersistentStore	
  
Questa	
  classe	
  ha	
  il	
  compito	
  di	
  gestire	
  uno	
  o	
  più	
  sistemi	
  di	
  memorizzazione	
  (tabelle)	
  associati	
  al	
  loro	
  
managed	
  object	
  model,	
  o	
  a	
  più	
  “persistent	
  store”.	
  
I	
  tipi	
  di	
  memorizzazione	
  per	
  la	
  persistenza	
  dei	
  dati	
  si	
  suddividono	
  in:	
  
        ⇒ NSSQLiteStoreType	
  
        ⇒ NSBinaryStoreType	
  
        ⇒ NSInMemoryStoreType	
  
Nel	
  seguente	
  esempio	
  di	
  codice	
  è	
  mostrata	
  la	
  procedura	
  di	
  assegnazione	
  del	
  persistent	
  store	
  :	
  
        1. Definizione	
  della	
  memorizzazione	
  con	
  il	
  caricamento	
  del	
  database	
  SQLite	
  dalla	
  cartella	
  
                   Document	
  dell'applicazione.	
  
       	
                                                                                                                                              3-­‐31	
  
2. Creazione	
  dell'URL	
  dal	
  database	
  e	
  dell'istanza	
  del	
  NSPersistentStoreCoordinator	
  
           3. Inizializzazione	
  da	
  parte	
  del	
  coordinator	
  dello	
  store	
  coordinator	
  usando	
  un'istanza	
  del	
  
              managed	
  object	
  model	
  	
  
	
  

NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: @"photo.sqlite"]];//CompactNavigator.sqlite
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];

	
  
	
  

3.3.5 Uso	
  dei	
  dati	
  provenienti	
  da	
  un	
  web	
  service	
  
Una	
  delle	
  caratteristiche	
  richieste	
  maggiormente	
  per	
  quanto	
  concerne	
  lo	
  sviluppo	
  di	
  applicazioni	
  per	
  
dispositivi	
  mobili	
  è	
  la	
  possibilità	
  di	
  interagire	
  e	
  scambiare	
  informazioni	
  tramite	
  web,	
  ad	
  esempio	
  per	
  
mezzo	
   dell'iterazione	
   con	
   i	
   web	
   services	
   ovvero	
   servizi	
   web	
   resi	
   disponibili	
   gratuitamente	
   e	
   non,	
   da	
  
server	
  e	
  aziende	
  in	
  località	
  remote	
  rispetto	
  al	
  dispositivo	
  mobile.	
  
Solitamente,	
  gli	
  ambienti	
  di	
  sviluppo	
  più	
  recenti	
  sono	
  predisposti	
  già	
  per	
  la	
  creazione	
  di	
  applicativi	
  di	
  
questo	
   tipo:	
   Xcode	
   che	
   è	
   il	
   tool	
   usato	
   per	
   le	
   applicazioni	
   su	
   Iphone,	
   non	
   dispone	
   di	
   un	
   ambiente	
  
intrinseco	
   per	
   l'elaborazione	
   di	
   applicativi	
   progettati	
   proprio	
   per	
   il	
   cosiddetto	
   “consumo	
   ”	
   dei	
   dati	
  
provenienti	
   dai	
   web	
   services,	
   quindi	
   il	
   procedimento	
   deve	
   essere	
   eseguito	
   manualmente	
   dal	
  
programmatore.	
  
I	
   messaggi	
   forniti	
   da	
   questi	
   servizi,	
   seguono	
   la	
   struttura	
   dell’XML,	
   quindi,	
   un	
   qualsiasi	
   programma	
   che	
  
li	
   vorrà	
   utilizzare,	
   dovrà	
   eseguire	
   un'analisi	
   del	
   messaggio,	
   prelevando	
   le	
   informazioni	
   utili	
   dal	
  
messaggio	
  inviato	
  (parsing).	
  
L'XML	
  utilizza	
  dei	
  marcatori,	
  chiamati	
  tag,	
  per	
  assegnare	
  una	
  semantica	
  al	
  testo.	
  È	
  molto	
  rigido	
  sulla	
  
sintassi	
  da	
  seguire	
  rispetto	
  all'HTML	
  ed	
  è	
  pertanto	
  necessario	
  rispettare	
  alcune	
  regole:	
  
        ⇒ I	
  tag	
  non	
  possono	
  iniziare	
  con	
  numeri	
  o	
  caratteri	
  speciali	
  e	
  non	
  possono	
  contenere	
  spazi;	
  	
  
        ⇒ I	
  tag	
  devono	
  essere	
  bilanciati,	
  ovvero	
  non	
  sono	
  consentiti	
  errori	
  di	
  annidamento.	
  
        ⇒ È	
  un	
  linguaggio	
  case	
  sensitive	
  quindi	
  i	
  tag	
  scritti	
  con	
  lo	
  stesso	
  nome,	
  ma	
  con	
  caratteri	
  maiuscoli	
  
            o	
  minuscoli	
  risultano	
  durante	
  il	
  parsing	
  essere	
  diversi.	
  	
  
	
  L'utente	
   che	
   vorrà	
   quindi	
   leggere	
   un	
   determinato	
   messaggio	
   dovrà	
   far	
   eseguire	
   al	
   programma	
  
un’analisi	
  di	
  ogni	
  singolo	
  tag,	
  conoscendo	
  a	
  priori	
   la	
  sua	
  struttura	
  e	
  la	
  sintassi	
  della	
  stringa	
  di	
  richiesta	
  
da	
  inviare	
  al	
  server	
  per	
  ottenere	
  una	
  risposta	
  corretta.	
  
	
  	
  



                                                                                                                                       	
  




           	
                                                                                                                                                 3-­‐32	
  
 
	
  

Figura	
  7:	
  In	
  alto:	
  esempio	
  di	
  request	
  In	
  basso:	
  response	
  	
  del	
  web	
  service	
  

Per	
   permettere	
   la	
   lettura	
   dei	
   messaggi	
   XML	
   provenienti	
   da	
   questi	
   servizi,	
   in	
   questo	
   progetto	
   è	
   stato	
  
scelto	
   di	
   utilizzare	
   la	
   classe	
   NSXmlParser	
   che	
   rende	
   disponibili	
   metodi	
   per	
   la	
   lettura	
   e	
   l’analisi	
   dei	
  
messaggi	
  XML.	
  

Per	
  rendere	
  operativa	
  un'applicazione	
  che	
  legga	
  un	
  messaggio	
  da	
  web	
  service,	
  si	
  rende	
  necessaria	
  la	
  
creazione	
   di	
   una	
   classe	
   che	
   possa	
   replicare	
   la	
   struttura	
   dei	
   dati	
   e	
   degli	
   attributi	
   prelevati	
   da	
   XML	
   in	
  
modo	
   tale	
   da	
   renderli	
   fruibili	
   dal	
   programma	
   cosicché	
   ogni	
   sua	
   istanza	
   rappresenti	
   un	
   elemento	
   del	
  
documento.
	
  
#import <Foundation/Foundation.h>

@interface TagPoint : NSObject {
@private NSString *namePoint;
@private NSString *descriptPoint;//aggiunto ora
@private NSNumber *latPoint;
@private NSNumber *longitPoint;
@private NSString *urlWiki;
}

@property             (nonatomic,retain)                    NSString *namePoint;
@property             (nonatomic,retain)                    NSString *descriptPoint;
@property             (nonatomic,retain)                    NSNumber *latPoint;
@property             (nonatomic,retain)                    NSNumber *longitPoint;

-(id)init;
-(void) setLatPoint:(NSNumber *)lat;
-(void) setLongitPoint:(NSNumber *)longit;
-(void) setNamePoint:(NSString *) name;
-(void) setDescriptionPoint:(NSString *)descript;
-(void) setURLWiki:(NSString *)link
-(void) setLatPoint:(NSNumber *)lat;
-(void) setLongitPoint:(NSNumber *)longit;
       	
                                                                                                                                                            3-­‐33	
  
-(void) setNamePoint:(NSString *) name;
-(void) setDescriptionPoint:(NSString *)descript;

#import "TagPoint.h"

@implementation TagPoint

@synthesize namePoint, descriptPoint, urlWiki, latPoint, longitPoint;
//inizializzo i field interni
-(id)init
{
namePoint = [[NSString alloc] init];
descriptPoint =[[NSString alloc]init];
urlWiki = [[NSString alloc]init];
latPoint = [[NSNumber alloc] init];
longitPoint = [[NSNumber alloc] init];
return self;
}
-(void) setLatPoint:(NSNumber *)lat
{
latPoint = lat;
}
-(void) setLongitPoint:(NSNumber *)longit
{
longitPoint = longit;
}
-(void) setNamePoint:(NSString *) name
{
namePoint = name;
}
-(void) setDescriptionPoint:(NSString *)descript
{
descriptPoint = descript;
}

Codice	
  5:	
  header	
  e	
  implementazione	
  del	
  file	
  per	
  contenere	
  gli	
  elementi	
  XML	
  

3.3.5.1 Parsing	
  del	
  messaggio	
  
Per	
  eseguire	
  il	
  parsing	
  del	
  messaggio	
  XML	
  ricevuto	
  da	
  un	
  generico	
  web	
  service,	
  deve	
  essere	
  creata	
  la	
  
stringa	
  di	
  “request”	
  ovvero	
  un’istanza	
  della	
  classe	
  NSURL	
  che	
  è	
  quella	
  delegata	
  a	
  comporre	
  la	
  richiesta	
  
da	
   inviare	
   al	
   web	
   service,	
   poi	
   successivamente,	
   deve	
   essere	
   creato	
   l’istanza	
   dell’oggetto	
   che	
   servirà	
   ad	
  
analizzare	
   il	
   messaggio	
   di	
   risposta,	
  ovvero	
  della	
  classe	
  NSXmlParser	
  che	
  è	
  inizializzata	
   con	
   l’oggetto	
   di	
  
tipo	
  NSURL	
  creato	
  precedentemente.	
  

A	
   questo	
   punto	
   il	
   programmatore	
   potrà	
   impostare	
   la	
   proprietà	
   di	
   delegate	
   dell’oggetto	
   di	
   tipo	
  
NSXmlParser	
   inizializzato	
   in	
   precedenza,	
   con	
   un’istanza	
   di	
   una	
   classe	
   che	
   implementi	
   il	
   protocollo	
  
NSXmlParserDelegate	
  che	
  serve	
  ad	
  eseguire	
  il	
  parsing	
  del	
  messaggio.	
  

NSURL *url = [NSURL URLWithString:[NSString
      	
                                                                                                                                                   3-­‐34	
  
stringWithFormat:@"http://ws.geonames.org/findNearbyWikipedia?lat=%@&lng=%@",latStr
,longitStr]];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
[parser autorelease];
	
  
	
  

Il	
   protocollo	
   NSXmlParserDelegate	
   dovrà	
   contenere	
   dei	
   metodi	
   che	
   potranno	
   oppure	
   non,	
   essere	
  
implementati,	
  tra	
  i	
  quali,	
  i	
  più	
  rilevanti	
  risultano	
  essere:	
  :	
  

       ⇒ -­(void)parser:(NSXMLParser	
  *)parser	
  didStartElement:(NSString	
  *)elementName	
  
         namespaceURI:(NSString	
  *)	
  namespaceURI	
  qualifiedName:(NSString	
  *)qName	
  
         attributes:	
  (NSDictionary	
  *)attributeDict
       ⇒ -­(void)parser:(NSXMLParser	
  *)parser	
  foundCharacters:(NSString	
  *)string	
  
       ⇒ -­(void)parser:(NSXMLParser	
  *)parser	
  didEndElement:(NSString	
  *)elementName	
  
         namespaceURI:(NSString	
  *)namespaceURI	
  qualifiedName:(NSString	
  *)qName	
  
	
  
Il	
  primo	
  metodo	
  sarà	
  richiamato	
  quando	
  s’inizierà	
  il	
  parsing	
  del	
  messaggio,	
  con	
  lo	
  scopo	
  di	
  individuare	
  
le	
  “aperture”	
  di	
  nuovi	
  tag,	
  e	
  inizializzare	
  le	
  eventuali	
  istanze	
  di	
  classi	
  usate	
  durante	
  il	
  parsing.	
  

A	
   questo	
   punto	
   il	
   programma	
   richiamerà	
   il	
   secondo	
   metodo	
   che	
   riconoscerà	
   i	
   valori	
   dei	
   tag	
   e	
   li	
  
assocerà	
  alla	
  variabile	
  di	
  tipo	
  NSDictionary.	
  

Quando	
   poi	
   il	
   programma	
   riconoscerà	
   la	
   fine	
   di	
   un	
   tag	
   allora	
   richiamerà	
   l’ultimo	
   metodo	
   il	
   quale	
  
assegnerà	
  i	
  valori	
  letti	
  ad	
  esempio	
  a	
  un	
  array	
  di	
  memorizzazione	
  temporanea	
  dei	
  dati	
  che	
  potrà	
  essere	
  
utile	
  per	
  elaborazioni	
  dei	
  dati	
  successive.	
  

3.3.6 Il	
  frame	
  work	
  Mapkit	
  
Queste	
   librerie	
   permettono	
   di	
   usufruire	
   delle	
   funzionalità	
   e	
   della	
   visualizzazione	
   delle	
   mappe	
  
similmente	
  a	
  quello	
  che	
  avviene	
  già	
  nell’applicazione	
  preinstallata	
  nell’Iphone.	
  Grazie	
  a	
  questo	
  frame	
  
work	
   è	
   possibile	
   delegare	
   allo	
   sviluppatore	
   la	
   creazione	
   di	
   viste	
   personalizzate	
   della	
   mappa	
   oppure	
  
gestire	
  le	
  annotazioni,	
  fornendo	
  un	
  valido	
  strumento	
  di	
  sviluppo	
  di	
  applicazioni	
  al	
  programmatore.	
  

3.3.6.1 La	
  classe	
  MKMapView	
  
E’	
   la	
   classe	
   principale	
   della	
   libreria	
   Mapkit	
   ed	
   è	
   derivata	
   dalla	
   classe	
   UIKit,	
   cosicché	
   è	
   facilmente	
  
implementabile	
  nelle	
  classi	
  usate	
  principalmente	
  per	
  elaborare	
  oggetti	
  grafici.	
  

Per	
  un	
  corretto	
  funzionamento	
  del	
  progetto	
  in	
  cui	
  si	
  vuole	
  includere	
  questo	
  frame	
  work,	
  è	
  necessario	
  
dichiarare	
  espressamente	
  l’uso	
  di	
  questa	
  libreria	
  nella	
  classe	
  in	
  cui	
  la	
  si	
  implementa,	
  aggiungendo	
  sia	
  
all’header	
  della	
  classe	
  il	
  codice	
  <MapKit/MapKit.h>,	
  sia	
  nelle	
  impostazioni	
  del	
  progetto.	
  	
  
A	
  questo	
  punto	
  potrò	
  procedere	
  con	
  la	
  dichiarazione	
  dell’istanza	
  di	
  questa	
  classe,	
  impostando	
  anche	
  le	
  
sue	
  proprietà:	
  
MKMapView *mapView = [[[MKMapView alloc] initWithFrame: [UIScreen
mainScreen].applicationFrame] autorelease];
[self.view addSubview:mapView];
	
  

3.3.6.2 La	
  structure	
  MKCoordinateRegion	
  
Questo	
   elemento	
   della	
   Mapkit	
   è	
   una	
   structure	
   (struttura	
   dati),	
   che	
   contiene	
   al	
   suo	
   interno	
   gli	
   elementi	
  
necessari	
  al	
  momento	
  del	
  caricamento	
  di	
  una	
  mappa	
  	
  quali	
  	
  il	
  centro	
  della	
  mappa	
  contenuti	
  nella	
  struct	
  
CLLocationCoordinate2D(latitudine,	
   longitudine)	
   e	
   lo	
   zoom	
   contenuto	
   invece	
   nella	
   struct	
  	
  

       	
                                                                                                                                                    3-­‐35	
  
MKCoordinateSpan	
   composto	
   da	
   due	
   valori	
   di	
   tipo	
   CLLocationDegrees	
   corrispondenti	
   a	
   valori	
   di	
   tipo	
  
double.	
  
	
  
typedef struct {
CLLocationCoordinate2D center;
MKCoordinateSpan span;
} MKCoordinateRegion;


typedef struct {
CLLocationDegrees latitudeDelta;
CLLocationDegrees longitudeDelta;
} MKCoordinateSpan;
	
  
	
  

3.3.6.3 Il	
  protocollo	
  MKAnnotation	
  
I	
  punti	
  che	
  si	
  vogliono	
  visualizzare	
  sulla	
  mappa	
  vanno	
  sotto	
  il	
  nome	
  di	
  “annotations”.	
  
Un’annotation	
  è	
  composta	
  da	
  un	
  data	
  model	
  che	
  specifica	
  il	
  titolo,	
  il	
  sottotitolo,	
  i	
  valori	
  di	
  	
  
latitudine/longitudine	
  del	
  punto	
  e	
  una	
  “view”	
  che	
  altro	
  non	
  è	
  che	
  la	
  rappresentazione	
  del	
  data	
  model.	
  
Il	
  protocollo	
  MKAnnotation	
  descrive	
  quindi	
  il	
  modello	
  della	
  descrizione	
  del	
  punto:	
  

@protocol MKAnnotation <NSObject>
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@optional
- (NSString *)title;
- (NSString *)subtitle;
@end
	
  
	
  

In	
   sintesi,	
   questo	
   protocollo	
   stabilisce	
   che	
   ogni	
   “annotation”	
   può	
   essere	
   abilitata	
   a	
   specificare	
   le	
   sue	
  
coordinate	
  ed	
  eventualmente	
  impostare	
  il	
  titolo	
  e	
  il	
  sottotitolo.	
  	
  
Per	
   creare	
   quindi	
   una	
   classe	
   per	
   le	
   annotazioni	
   di	
   una	
   mappa,	
   si	
   dovrà	
   obbligatoriamente	
  
implementare	
  questo	
  protocollo,	
  come	
  evidenziato	
  nel	
  seguente	
  esempio:	
  
	
  
@interface MyAnnotation : NSObject<MKAnnotation> {

CLLocationCoordinate2D coordinate;
NSString *name;
NSString *title;
NSString *descr;
NSString *link;
}

@property          (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property          (nonatomic,retain) NSString *name;
@property          (nonatomic,retain) NSString *title;
@property          (nonatomic,retain) NSString *descr;

       	
                                                                                                                                                  3-­‐36	
  
@property (nonatomic, retain)NSString *link;



      •      (id) initWithCoords:(CLLocationCoordinate2D) coords name:(NSString*) inputName
             descr:(NSString*) inputDescr link:(NSString*) inputLink ;

@implementation MyAnnotation

@synthesize coordinate, name, title, descr, link;

- (id) initWithCoords:(CLLocationCoordinate2D) coords name:(NSString*) inputName
descr:(NSString*)inputDescr link:(NSString*)inputLink
{
self = [super init];
if (self != nil) {
coordinate = coords;
self.name = inputName;
self.title = inputName;
self.descr = inputDescr;
self.link = inputLink;
}
return self;
}
@end

Codice	
  6:	
  Esempio	
  d’implementazione	
  del	
  protocollo	
  MKAnnotation	
  

3.3.6.4 La	
  classe	
  MKAnnotationView	
  
E’	
  la	
  classe	
  che	
  si	
  occupa	
  della	
  visualizzazione	
  delle	
  annotazioni	
  sulla	
  mappa.	
  

Per	
   rendere	
   possibile	
   l’iterazione	
   dell’istanza	
   di	
   questa	
   classe	
   con	
   la	
   mappa	
   è	
   necessario	
   settare	
   la	
   sua	
  
proprietà	
  di	
  delegate	
  sull’istanza	
  della	
  vista	
  della	
  mappa	
  ed	
  avere	
  un	
  metodo	
  che	
  restituisca	
  un	
  oggetto	
  
di	
  tipo	
  UIView	
  per	
  ogni	
  “annotation”	
  ottenuta.	
  

@property (nonatomic, assign) id <MKMapViewDelegate> delegate;
	
  
(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id
<MKAnnotation>)annotation;
	
  
Codice	
  7:	
  dichiarazione	
  della	
  proprietà	
  delegate	
  

3.3.6.5 La	
  classe	
  MKUserLocation	
  
Questa	
  classe	
  è	
  usata	
  per	
  la	
  visualizzazione	
  della	
  localizzazione	
  dell’utente.	
  	
  	
  

3.3.6.6 La	
  classe	
  MKPinAnnotationView	
  	
  
Deriva	
   dalla	
   classe	
   MKAnnotationView	
   e	
   rappresenta	
   il	
   “pin”	
   grafico	
   in	
   una	
   mappa,	
   ossia	
  
quell'elemento	
   che	
   segnala	
   un	
   punto	
   d’interesse	
   dell'utente	
   sulla	
   mappa	
   disegnata	
   nella	
   vista,	
   come	
  
mostrato	
  in	
  questo	
  esempio	
  di	
  codice:	
  
	
  
..

      	
                                                                                                                                                       3-­‐37	
  
MKPinAnnotationView* annView = (MKPinAnnotationView*)[self.mapView
dequeueReusableAnnotationViewWithIdentifier:identifier];
if(nil == annView) {
annView = [[[MKPinAnnotationView alloc] initWithAnnotation:myAnnotation
reuseIdentifier:identifier] autorelease];
}
[annView addObserver:self
forKeyPath:@"selected"
options:NSKeyValueObservingOptionNew
context:GMAP_ANNOTATION_SELECTED];
[annView setPinColor:MKPinAnnotationColorGreen];
….
	
  
Codice	
  8:	
  esempio	
  di	
  implementazione	
  della	
  MKPinAnnotationView	
  




                           	
  	
  

Figura	
  8:	
  Esempio	
  grafico	
  della	
  classe	
  MKPinAnnotationView	
  

	
  

3.3.7 La	
  libreria	
  dell’”Augmented	
  Reality”(ARKit)	
  
L'Iphone	
  ARKit	
  è	
  un	
  progetto	
  open	
  source,	
  pubblicato	
  verso	
  la	
  metà	
  di	
  Luglio	
  2009,	
  composto	
  da	
  un	
  
set	
  di	
  classi	
  che	
  forniscono	
  alle	
  applicazioni	
  in	
  cui	
  è	
  implementato,	
  il	
  modello	
  della	
  “Realtà	
  Aumentata”.	
  	
  
Questa	
   caratteristica	
   permette	
   di	
   visualizzare	
   delle	
   informazioni	
   aggiuntive	
   all'osservatore	
  
sull’ambiente	
   a	
   lui	
   circostante	
   tramite	
   la	
   fotocamera	
   dell'Iphone	
   che	
   è	
   utilizzata	
   come	
   mezzo	
   per	
   la	
  
localizzazione	
  dei	
  punti	
  di	
  interesse	
  presenti.	
  
Questo	
   risultato	
   è	
   possibile	
   grazie	
   all'iterazione	
   fra	
   più	
   periferiche	
   già	
   presenti	
   nell'Iphone:	
   il	
  
ricevitore	
  GPS,	
  la	
  bussola	
  e	
  l'accelerometro,	
  come	
  mostrato	
  nello	
  schema	
  sottostante.	
  
	
  




                                                                                                                                                	
  

       	
                                                                                                                                              3-­‐38	
  
Figura	
  9:	
  Schema	
  di	
  funzionamento	
  libreria	
  AR	
  

       ⇒ Il	
  ricevitore	
  GPS	
  servirà	
  a	
  ottenere	
  la	
  posizione	
  istantanea	
  del	
  telefono;	
  
       ⇒ La	
   bussola	
   per	
   carpire	
   la	
   posizione	
   dell'utente	
   in	
   modo	
   tale	
   da	
   gestire	
   il	
   layer	
   virtuale	
  
         sovrapposto	
  all'obiettivo,	
  relativo	
  ai	
  punti	
  d’interesse;	
  
       ⇒ L'accelerometro	
  per	
  ottenere	
  l'orientamento	
  relativo	
  dell'utente	
  (inclinazione	
  dell'Iphone);	
  
       ⇒ La	
  fotocamera	
  per	
  far	
  interagire	
  l'Iphone	
  con	
  l'ambiente	
  reale.	
  
	
  

3.3.7.1 Struttura	
  della	
  libreria	
  




                                           	
  
Figura	
  10:	
  Organizzazione	
  della	
  libreria	
  AR	
  

La	
   classe	
   è	
   composta	
   di	
   due	
   view	
   controller,	
   l’ARViewController	
   e	
   l’ARGeoViewController,	
   in	
   cui	
   il	
  
primo	
   è	
   derivato	
   direttamente	
   dalla	
   classe	
   UIViewController,	
   che	
   si	
   occupa	
   della	
   gestione	
  
dell’interfaccia	
  grafica,	
  mentre	
  il	
  secondo	
  è	
  figlio	
  dell’ARViewController.	
  
L’ARViewController	
   implementa	
   i	
   protocolli	
   per	
   la	
   gestione	
   dell'accelerometro	
  
(UIAccelerometerDelegate),	
   del	
   ricevitore	
   GPS	
   (CLLocationManagerDelegate)	
   e	
   dichiara	
   un	
   suo	
  
protocollo	
   (ARViewDelegate)	
   in	
   cui	
   è	
   definito	
   un	
   metodo	
   (viewForCoordinate:)	
   che	
   ha	
   in	
   ingresso	
  
un'istanza	
   della	
   classe	
   ARCoordinate	
   e	
   che	
   ritorna	
   un	
   elemento	
   grafico	
   di	
   tipo	
   UIView	
   che	
   serve	
   a	
  
“costruire”	
  l’interfaccia	
  grafica	
  finale	
  per	
  la	
  visualizzazione	
  dell’”Augmented	
  Reality”.	
  
Quest’ultima	
   classe,	
   si	
   occupa	
   della	
   gestione	
   dell'UIImagePickerController	
   che	
   è	
   il	
   controller	
   usato	
   per	
  
gestire	
   l'obiettivo	
   fotografico	
   dell'Iphone,	
   dell'inizializzazione	
   del	
   ricevitore	
   GPS,	
   della	
   bussola	
   e	
  
costruisce	
  in	
  maniera	
  gerarchica	
  la	
  visualizzazione	
  della	
  maschera,	
  impostando	
  l'area	
  del	
  display	
  del	
  
telefono,	
  del	
  caricamento	
  dei	
  punti	
  d’interesse	
  nella	
  memoria	
  e	
  della	
  loro	
  visualizzazione.	
  
La	
   sua	
   figlia,	
   ossia	
   la	
   classe	
   ARGeoViewController,	
   aggiunge	
   ai	
   metodi	
   già	
   implementati	
   dalla	
   classe	
  
madre,	
   la	
   localizzazione	
   del	
   centro	
   delle	
   coordinate	
   corrispondente	
   alla	
   posizione	
   dell’utente	
   nello	
  
spazio.	
  
Le	
   classi	
   invece	
   ARCoordinate	
   e	
   ARGeoCoodinate,	
   fungono	
   da	
   “contenitori”	
   dei	
   dati	
   memorizzati	
  
attraverso	
  i	
  view	
  controllers,	
  fornendo	
  dei	
  metodi	
  per	
  la	
  loro	
  elaborazione.	
  	
  	
  
	
  


4 REALIZZAZIONE	
  
	
  
       	
                                                                                                                                               4-­‐39	
  
4.1 Specifiche	
  
L’obiettivo	
   del	
   progetto	
   è	
   di	
   sviluppare	
   e	
   realizzare	
   un	
   applicativo	
   in	
   grado	
   di	
   riconoscere	
   tramite	
  
l’obiettivo	
   della	
   macchina	
   fotografica	
   integrata	
   nell’Iphone	
   i	
   punti	
   d’interesse,	
   inseriti	
   dall’utente	
   nella	
  
memoria	
   del	
   telefono	
   e	
   non,	
   nelle	
   vicinanze	
   dell’utente,	
   integrando	
   al	
   tempo	
   stesso	
   nel	
   programma	
  
alcuni	
   elementi	
   caratteristici	
   di	
   un’applicazione	
   di	
   navigazione,	
   quali	
   ad	
   esempio	
   la	
   visualizzazione	
  
della	
   mappa,	
   la	
   tracciatura	
   del	
   percorso	
   compiuto	
   durante	
   un	
   intervallo	
   di	
   tempo	
   o	
   anche	
   la	
  
localizzazione	
  sulla	
  mappa	
  dei	
  punti	
  d’interesse	
  dell’utente.	
  

Come	
   specifica	
   imposta	
   in	
   un	
   secondo	
   momento,	
   è	
   stata	
   quella	
   di	
   creare	
   un	
   sistema	
   “leggero”	
   in	
  
termini	
   di	
   risorse	
   richieste	
   al	
   sistema,	
   in	
   quanto	
   si	
   doveva	
   tenere	
   conto	
   delle	
   prestazioni	
   ridotte	
   del	
  
dispositivo	
   mobile	
   sul	
   quale	
   si	
   vanno	
   a	
   caricare	
   i	
   dati,	
   cercando	
   di	
   colmare	
   queste	
   lacune	
   con	
   lo	
  
sfruttamento	
  della	
  rete,	
  trattata	
  come	
  una	
  risorsa	
  aggiuntiva	
  per	
  l’estrazione	
  dei	
  dati	
  da	
  elaborare.	
  

Per	
  realizzare	
  quindi	
  un	
  sistema	
  di	
  questo	
  tipo	
  si	
  è	
  dovuto	
  focalizzare	
  l’attenzione	
  sugli	
  elementi	
  che	
  
avrebbero	
  caratterizzato	
  questo	
  software:	
  	
  

          ⇒   Un	
  database	
  di	
  memorizzazione	
  dei	
  punti	
  d’interesse	
  specificati	
  dall’utente;	
  
          ⇒   L’integrazione	
  della	
  fotocamera	
  nell’applicativo;	
  
          ⇒   L’implementazione	
  dell’”Augmented	
  Reality”;	
  	
  
          ⇒   L’utilizzo	
  della	
  rete	
  per	
  il	
  caricamento	
  di	
  dati	
  provenienti	
  dai	
  web	
  services;	
  
          ⇒   La	
   visualizzazione	
   di	
   una	
   mappa	
   e	
   la	
   disponibilità	
   di	
   funzioni	
   tipiche	
   dei	
   software	
   di	
  
              navigazione.	
  

Le	
  motivazioni	
  di	
  queste	
  scelte	
  sono	
  state	
  le	
  seguenti:	
  

          •   La	
  necessità	
  di	
  avere	
  un	
  sistema	
  di	
  tabelle	
  per	
  la	
  memorizzazione	
  interna	
  dei	
  punti	
  d’interesse	
  
              consente	
  al	
  programma	
  stesso	
  di	
  riconoscerli,	
  permettendo	
  al	
  sistema	
  di	
  sfruttare	
  in	
  maniera	
  
              corretta	
  le	
  potenzialità	
  della	
  “realtà	
  aumentata”	
  implementata	
  sull’Iphone.	
  
          •   La	
   gestione	
   della	
   fotocamera	
   integrata	
   nel	
   programma	
   consente	
   all’utente	
   di	
   non	
   dover	
   uscire	
  
              dall’applicativo	
   per	
   scattare	
   una	
   foto	
   al	
   suo	
   punto	
   d’interesse	
   e	
   anche	
   in	
   questo	
   caso	
   di	
  
              interagire	
  con	
  le	
  librerie	
  dell’Augmented	
  Reality;	
  
          •   L’uso	
  della	
  realtà	
  aumentata	
  permette	
  di	
  soddisfare	
  gli	
  obiettivi	
  del	
  progetto	
  interponendo	
  tra	
  
              l’osservatore	
   e	
   la	
   fotocamera	
   del	
   dispositivo,	
   un	
   “layer”	
   che	
   consentirà	
   di	
   indicare	
   e	
  
              riconoscere	
  i	
  punti	
  d’interesse.	
  
          •   L’utilizzo	
  dei	
  web	
  services	
  in	
  linea	
  generica	
  permetterà	
  al	
  programma,	
  una	
  volta	
  concluso,	
  di	
  
              sfruttare	
  la	
  rete	
  come	
  un’enorme	
  fonte	
  di	
  dati,	
  integrando	
  le	
  informazioni	
  già	
  in	
  suo	
  possesso	
  
              con	
  quelle	
  presenti	
  su	
  database	
  remoti.	
  

4.1.1         Memorizzazione	
  persistente	
  dei	
  punti	
  d’interesse	
  e	
  integrazione	
  nel	
  programma	
  dell’uso	
  
              della	
  fotocamera	
  	
  
	
  




       	
                                                                                                                                                    4-­‐40	
  
 
Figura	
  11:	
  Rappresentazione	
  del	
  sistema	
  iniziale	
  di	
  memorizzazione	
  

4.1.1.1 Un	
  approccio	
  alla	
  memorizzazione	
  dei	
  dati	
  
La	
   base	
   di	
   partenza	
   è	
   stata	
   un	
   database,	
   contenente	
   una	
   sola	
   tabella	
   che	
   avrebbe	
   memorizzato	
   solo	
  
delle	
   ipotetiche	
   informazioni	
   in	
   forme	
   testuali	
   e	
   numeriche	
   relative	
   alle	
   coordinate	
   geografiche	
   e	
   le	
  
descrizioni	
   di	
   eventuali	
   punti	
   d’interesse.	
   Per	
   rendere	
   fruibili	
   i	
   dati,	
   si	
   sono	
   dovute	
   creare	
   anche	
   le	
  
relative	
  interfacce	
  grafiche	
  in	
  modo	
  da	
  permettere	
  le	
  iterazioni	
  fra	
  la	
  persona	
  e	
  il	
  programma.	
  

Per	
  costruirle,	
  ci	
  si	
  è	
  appoggiati	
  all’Interface	
  Builder,	
  creando	
  un	
  insieme	
  di	
  form,	
  ognuna	
  delle	
  quali	
  
progettata	
  per	
  visualizzare,	
  aggiornare,	
  inserire	
  o	
  cancellare	
  i	
  dati	
  presenti	
  in	
  memoria.	
  

Questo	
   sistema	
   però	
   è	
   risultato	
   essere	
   incompleto	
   perché	
   mancava	
   di	
   un’ulteriore	
   caratterizzazione	
  
delle	
  informazioni	
  sui	
  punti	
  d’interesse:	
  la	
  possibilità	
  di	
  associare	
  a	
  un	
  punto	
  una	
  foto.	
  

Di	
   conseguenza,	
   allora	
   al	
   database	
   esistente,	
   si	
   è	
   aggiunta	
   un’altra	
   tabella	
   con	
   lo	
   scopo	
   di	
   utilizzarla	
  
nella	
  memorizzazione	
  di	
  un’eventuale	
  foto	
  per	
  il	
  punto	
  d’interesse	
  stesso.	
  

4.1.1.2 Il	
  sistema	
  finale	
  di	
  memorizzazione	
  dei	
  dati	
  
La	
  memorizzazione	
  dei	
  dati	
  è	
  da	
  considerarsi	
  come	
  un	
  elemento	
  necessario	
  poiché	
  senza	
  di	
  essa,	
  non	
  
ci	
   sarebbe	
   la	
   possibilità	
   di	
   soddisfare	
   tutte	
   le	
   specifiche	
   stabilite	
   all’inizio	
   del	
   progetto	
   e	
   soprattutto	
  
poter	
   usufruire	
   dei	
   dati	
   per	
   elaborazioni	
   successive,	
   come	
   ad	
   esempio	
   l’implementazione	
  
dell’Augmented	
  Reality	
  o	
  la	
  visualizzazione	
  dei	
  punti	
  su	
  una	
  mappa.	
  

Il	
  sistema	
  di	
  memorizzazione	
  finale	
  sarà	
  quindi	
  schematizzato	
  come	
  quello	
  rappresentato	
  nella	
  figura	
  
12.	
  




      	
                                                                                                                                                      4-­‐41	
  
 
Figura	
  12:	
  sistema	
  di	
  memorizzazione	
  finale	
  

Il	
  frame	
  work	
  utilizzato	
  per	
  la	
  gestione	
  delle	
  tabelle	
  è	
  stato	
  il	
  CoreData	
  nel	
  quale	
  sono	
  state	
  create	
  due	
  
tabelle:	
  

         ⇒ Photo	
  
         ⇒ PhotoPoint	
  

La	
   tabella	
   Photo	
   è	
   quella	
   in	
   cui	
   saranno	
   contenuti	
   i	
   dati	
   di	
   tipo	
   numerico	
   e	
   testuale	
   del	
   punto	
  
d’interesse	
   dell’utente,	
   mentre	
   la	
   tabella	
   PhotoPoint	
   sarà	
   quella	
   collegata	
   alla	
   prima	
   e	
   conterrà	
  
l’immagine	
  del	
  punto	
  stesso.	
  

Per	
   creare	
   un	
   programma	
   di	
   questo	
   tipo,	
   come	
   prima	
   cosa,	
   si	
   è	
   incluso	
   nelle	
   impostazioni	
   iniziali	
   di	
  
creazione,	
   il	
   frame	
   work	
   CoreData,	
   poi	
   in	
   seguito	
   si	
   sono	
   create	
   le	
   due	
   tabelle	
   appena	
   menzionate	
  
attraverso	
  l’editor	
  dell’Xcode.	
  

Seguendo	
   questi	
   passaggi,	
   il	
   tool	
   di	
   sviluppo	
   agevolerà	
   il	
   lavoro	
   dello	
   sviluppatore	
   impostando	
   nelle	
  
classi	
  create	
  di	
  default,	
  tutti	
  i	
  metodi	
  necessari	
  a	
  lavorare	
  sulle	
  tabelle	
  e	
  a	
  ricavare	
  il	
  contesto.	
  	
  




      	
                                                                                                                                                      4-­‐42	
  
 
Figura	
  13:	
  creazione	
  del	
  progetto	
  includendo	
  il	
  CoreData	
  


Nella	
  finestra	
  “Group	
  &	
  Files”,	
  nella	
  cartella	
  “Classes”	
  si	
  è	
  creato	
  un	
  gruppo	
  nominato	
  “Model”,	
  dove	
  è	
  
stato	
  creato	
  tramite	
  l’editor,	
  	
  il	
  database	
  “photo.xcdatamodel”e	
  dove	
  all’interno	
  dello	
  stesso	
  poi	
  sono	
  
state	
  inserite	
  le	
  due	
  tabelle	
  necessarie	
  nel	
  progetto:	
  Photo	
  e	
  PhotoPoint,	
  	
  

Tenendo	
   conto	
   delle	
   specifiche	
   precedentemente	
   imposte,	
   nella	
   tabella	
   Photo,	
   si	
   sono	
   inseriti	
   i	
  
seguenti	
  campi:	
  

         I.       namePhoto	
  	
  
         II.      latitudePhoto	
  
         III.     longitudePhoto	
  
         IV.      descriptionPhoto	
  
         V.       photoThumbnailImage	
  

Il	
  primo	
  indicherà	
  il	
  nome	
  del	
  punto	
  e	
  sarà	
  di	
  tipo	
  “String”	
  come	
  l’attributo	
  “descriptionPhoto”,	
  mentre	
  
i	
   campi	
   “latitudePhoto”	
   e	
   “longitudePhoto”	
   saranno	
   di	
   tipo	
   “Float”	
   e	
   l’ultimo,	
   ovvero	
   il	
  
“photoThumbnailImage”	
  sarà	
  di	
  tipo	
  “Transformer”.	
  

Nella	
   tabella	
   PhotoPoint	
   sarà	
   contenuto	
   solo	
   un	
   attributo	
   di	
   tipo	
   “Transformer”	
   che	
   conterrà	
  
l’immagine	
  da	
  associare	
  al	
  punto:	
  

             I.   photoPoint	
  



      	
                                                                                                                                          4-­‐43	
  
Le	
  due	
  tabelle	
  sono	
  state	
   collegate	
   creando	
  una	
  relazione	
  di	
  tipo	
  uno	
  a	
  uno	
  attraverso	
   l’identificazione	
  
nelle	
  due	
  entità	
  di	
  un	
  campo	
  di	
  tipo	
  “Relationships”	
  nominato	
  nella	
  prima	
  come	
  “photoPoint”	
  e	
  nella	
  
seconda	
  come	
  “photo”.	
  	
  

In	
  seguito	
  poi,	
  sono	
  stati	
  collegati	
  tramite	
  l’editor	
  come	
  presentato	
  nella	
  figura	
  sottostante.	
  




                                                                                                                                                                           	
  
Figura	
  14:	
  Editor	
  per	
  costruire	
  il	
  modello	
  xcdatamodel	
  

Sempre	
   all’interno	
   del	
   gruppo	
   “Model”,	
   si	
   sono	
   create	
   e	
   associate	
   due	
   classi,	
   chiamate	
   Photo	
   e	
  
PhotoPoint,	
   derivanti	
   dall’oggetto	
   NSManagedObject	
   con	
   lo	
   scopo	
   di	
   gestire	
   le	
   due	
   tabelle	
   appena	
  
create	
  e	
  in	
  cui	
  al	
  loro	
  interno	
  sono	
  state	
  inserite	
  le	
  proprietà	
  corrispondenti	
  ai	
  campi	
  di	
  ogni	
  singola	
  
entità.	
  	
  
Tenendo	
   presente	
   che	
   il	
   tipo	
   di	
   proprietà	
   della	
   classe	
   dovrà	
   essere	
   compatibile	
   con	
   quello	
  
corrispondente	
  della	
  tabella,	
  l’attributo	
  di	
  tipo	
  String	
  della	
  tabella	
  sarà	
  passato	
  nella	
  classe	
  con	
  il	
  tipo	
  
NSString,	
   il	
   tipo	
   Float	
   con	
   la	
   proprietà	
   di	
   tipo	
   NSNumber;	
   mentre	
   i	
   campi	
   di	
   tipo	
   “Relationships”,	
   nella	
  
classe,	
  saranno	
  descritti	
  da	
  una	
  proprietà	
  corrispondente	
  al	
  tipo	
  di	
  classe	
  sul	
  quale	
  quella	
  determinata	
  
relazione	
  andrà	
  a	
  collegarsi(ad	
  esempio:	
  in	
  Photo,	
  la	
  relazione	
  verso	
  PhotoPoint	
  sarà	
  descritta	
  da	
  una	
  
proprietà	
  della	
  classe	
  di	
  tipo	
  PhotoPoint	
  e	
  viceversa	
  ).	
  


#import <Foundation/Foundation.h>                                                     #import "Photo.h"
#import <CoreData/CoreData.h>                                                         #import "PhotoPoint.h"
@class PhotoPoint;
                                                                                      @implementation Photo
@interface UIImageToDataTransformer:
NSValueTransformer {                                                                  @dynamic namePhoto;
      	
                                                                                                                                                          4-­‐44	
  
@dynamic   latitudePhoto;
}                                                                                     @dynamic   longitudePhoto;
@end                                                                                  @dynamic   descriptionPhoto;
                                                                                      @dynamic   photoThumbnailImage;
@interface Photo : NSManagedObject {                                                  @dynamic   photoPoint;

}                                                                                     @end

@property (nonatomic,retain) NSString                                                 @implementation
*namePhoto;                                                                           UIImageToDataTransformer
@property (nonatomic,retain) NSNumber
*latitudePhoto;
@property (nonatomic,retain) NSNumber                                                 + (BOOL)allowsReverseTransformation {
*longitudePhoto;                                                                           return YES;
@property (nonatomic,retain) NSString                                                 }
*descriptionPhoto;
@property (nonatomic,retain) id                                                       + (Class)transformedValueClass {
photoThumbnailImage;                                                                        return [NSData class];
@property (nonatomic,retain) PhotoPoint                                               }
*photoPoint;

                                                                                      - (id)transformedValue:(id)value {
@end                                                                                        NSData *data =
	
                                                                                    UIImagePNGRepresentation(value);
                                                                                            return data;
                                                                                      }



                                                                                      - (id)reverseTransformedValue:(id)value {
                                                                                            UIImage *uiImage = [[UIImage alloc]
                                                                                      initWithData:value];
                                                                                            return [uiImage autorelease];
                                                                                      }

                                                                                      @end

                                                                                      	
  
Codice	
  9:	
  interfaccia	
  e	
  implementazione	
  della	
  classe	
  Photo	
  

#import <Foundation/Foundation.h>                                                     #import "PhotoPoint.h"

@class Photo;
                                                                                      @implementation PhotoPoint
@interface PhotoPoint : NSManagedObject {
                                                                                      @dynamic photo;
}                                                                                     @dynamic photoPoint;


      	
                                                                                                                      4-­‐45	
  
@property (nonatomic,retain) Photo *photo;                                       @end
@property (nonatomic, retain) id photoPoint;                                     	
  

@end
	
  
Codice	
  10:	
  Interfaccia	
  e	
  implementazione	
  della	
  classe	
  PhotoPoint	
  

Per	
   quanto	
   concerne	
   la	
   descrizione	
   della	
   proprietà	
   di	
   tipo	
   “Transformable”	
   che	
   avrà	
   come	
   valore	
  
UIImageToDataTransformer,	
   nell’interfaccia	
   la	
   si	
   dovrà	
   dichiarare	
   tramite	
   l’oggetto	
  
UIImageToDataTransformer	
   che	
   deriverà	
   da	
   NSValueTransformer	
   e	
   che	
   servirà	
   a	
   convertire	
  
l’immagine	
  in	
  una	
  forma	
  di	
  dato	
  memorizzabile	
  nella	
  tabella.	
  	
  	
  

4.1.1.2.1 Impostazione	
  dei	
  view	
  controller	
  
Per	
  visualizzare,	
  inserire,	
  modificare	
  o	
  eliminare	
  i	
  dati	
  presenti	
  nel	
  programma,	
  si	
  è	
  avuto	
  bisogno	
  di	
  
creare	
  svariati	
  view	
  controller,	
  derivanti	
  tutti	
  dalla	
  classe	
  UIViewController.	
  	
  

Nel	
  caso	
  di	
  questa	
  prima	
  parte,	
  si	
  sono	
  creati	
  cinque	
  view	
  controller	
  per	
  coprire	
  i	
  diversi	
  compiti	
  del	
  
sistema	
  di	
  memorizzazione:	
  

              I.     AddPhotoViewController	
  
              II.    PhotoDetailViewController	
  
              III.   PhotoViewController	
  
              IV.    EditingPhotoViewController	
  
              V.     RootViewController	
  

Il	
   primo	
   controller	
   sarà	
   utilizzato	
   per	
   inserire	
   nel	
   programma	
   un	
   nuovo	
   punto	
   d’interesse,	
   il	
  
“PhotoDetailViewController”	
  sarà	
  usato	
  per	
  visualizzare	
  il	
  dettaglio	
  di	
  ogni	
  punto	
  d’interesse	
  quando	
  
l’utente	
   partendo	
   dal	
   controller	
   iniziale	
   (RootViewController)	
   vorrà	
   visualizzare	
   i	
   dettagli;	
   il	
  
“PhotoViewController”	
   servirà	
   a	
   rappresentare	
   una	
   foto	
   a	
   schermo	
   intero;	
   il	
   penultimo	
   servirà	
   a	
  
modificare	
  le	
  informazioni	
  di	
  un	
  punto	
  già	
  inserito	
  mentre	
  il	
  “RootViewController”	
  fungerà	
  da	
  base	
  per	
  
tutto	
  il	
  sistema,	
  coordinando	
  l’attivazione	
  globale	
  di	
  tutte	
  le	
  form	
  .	
  

4.1.1.2.1.1 AddPhotoViewController	
  
Il	
  primo	
  controller	
  a	
  essere	
  stato	
  sviluppato	
  è	
  stato	
  questo,	
  poiché	
  è	
  quello	
  che	
  consente	
  di	
  aggiungere	
  
i	
  dati	
  alle	
  tabelle.	
  

Esso	
  è	
  derivato	
  dall’UIViewController	
  come	
  tutte	
  le	
  altre	
  form	
  che	
  saranno	
  analizzate	
  e	
  implementerà	
  i	
  
protocolli	
   di	
   UITextFieldDelegate,	
   UITextViewDelegate,	
   UIImagePickerControllerDelegate	
   e	
  
CLLocationManagerDelegate.	
  

	
  I	
   primi	
   due	
   serviranno	
   a	
   includere	
   alcuni	
   dei	
   metodi	
   propri	
   degli	
   oggetti	
   della	
   libreria	
   grafica	
  
UITextField	
                  e	
       UITextView	
             (in	
           questo	
      caso,	
            saranno	
             sfruttati	
       -­‐
(BOOL)textFieldShouldReturn:(UITextField	
   *)textField{}	
   per	
   disabilitare	
   la	
   tastiera	
   quando	
   l’utente	
  
premerà	
  il	
  tasto	
  “return”	
  sulla	
  textfield	
  e	
  -­‐(BOOL)textViewShouldEndEditing:(UITextView	
  *)textView{	
  
}	
  per	
  la	
  UITextView),	
  il	
  delegate	
  dell’UIImagePickerController	
  che	
  implementerà	
  i	
  metodi	
  per	
  gestire	
  le	
  
librerie	
   di	
   immagini	
   e	
   la	
   stessa	
   fotocamera,	
   presenti	
   nell’Iphone,	
   come	
   ad	
   esempio	
   i	
   metodi	
   -
(void)imagePickerController:(UIImagePickerController	
   *)picker	
   didFinishPickingImage:(UIImage	
  	
  
*)selectedImage	
                       editingInfo:(NSDictionary	
                    	
        *)editingInfo	
                 {}	
          e	
         -­‐	
  
(void)imagePickerControllerDidCancel:(UIImagePickerController	
  *)picker	
  {}	
  usati	
  per	
  gestire	
  il	
  primo	
  
l’editing	
  dell’immagine	
  ed	
  il	
  secondo	
  per	
  l’annullamento	
  di	
  una	
  determinata	
  azione	
  su	
  questo	
  elemento	
  
grafico	
  ed	
  infine	
  il	
  protocollo	
  CLLocationManagerDelegate	
  che	
  gestirà	
  il	
  ricevitore	
  GPS	
  integrato.	
  

Essendo	
  questo	
  controller	
  collegato	
  direttamente	
  a	
  un’interfaccia	
  visuale,	
  si	
  sono	
  dichiarati	
  gli	
  oggetti	
  
grafici	
   che	
   saranno	
   utilizzati,	
   prima	
   nell’interfaccia	
   della	
   classe,	
   poi	
   inizializzandoli	
   ed	
   elaborandoli	
  
nell’implementazione.	
  

       	
                                                                                                                                               4-­‐46	
  
 

4.1.1.2.1.1.1 Funzionamento	
  
Lo	
  scopo	
  di	
  questo	
  controller	
  è	
  di	
  dare	
  la	
  possibilità	
  all’utente	
  di	
  inserire	
  dei	
  dati	
  nuovi	
  in	
  memoria.	
  

I	
   campi	
   di	
   testo	
   riguardanti	
   le	
   coordinate	
   di	
   latitudine	
   e	
   longitudine	
   sono	
   impostati	
   durante	
   il	
  
caricamento	
   del	
   view	
   controller	
   leggendo	
   i	
   rispettivi	
   valori	
   dai	
   metodi	
   implementati	
   nel	
   protocollo	
  
CLLocationManagerDelegate,	
  mentre	
  gli	
  altri,	
  ovvero	
  quelli	
  della	
  descrizione	
  e	
  della	
  scelta	
  della	
  foto	
  da	
  
associare,	
  saranno	
  modificabili	
  dall’utente.	
  	
  

Potrà	
   essere	
   eseguita	
   la	
   scelta	
   della	
   foto	
   grazie	
   all’invocazione	
   dei	
   metodi	
   presenti	
   nel	
   protocollo	
  
UIImagePickerDelegate	
   che	
   gestiranno	
   la	
   libreria	
   fotografica	
   e	
   alla	
   classe	
   di	
   tipo	
   UIViewController	
   che	
  
li	
  richiamerà.	
  

A	
  questo	
  punto	
  l’utente	
  potrà	
  

          ⇒ Salvare	
   il	
   tutto	
   andando	
   a	
   richiamare	
   il	
   metodo	
   che	
   nel	
   codice	
   descritto	
   poco	
   più	
   sotto	
   prende	
  
            il	
  nome	
  di	
  “save”;	
  
          ⇒ 	
  Annullare	
  tutte	
  le	
  sue	
  azioni	
  invocando	
  sempre	
  da	
  interfaccia	
  grafica	
  il	
  metodo	
  “cancel”;	
  
          ⇒ Scegliere	
  le	
  foto	
  già	
  presenti	
  nella	
  libreria;	
  
          ⇒ 	
  Gestire	
   direttamente	
   la	
   fotocamera	
   per	
   scattare	
   nuove	
   foto	
   richiamando	
   il	
   metodo	
  
            “cameraClick:”.	
  

	
  Andando	
  ad	
  analizzare	
  più	
  approfonditamente	
  il	
  codice	
  dei	
  primi	
  due	
  metodi,	
  si	
  vedrà	
  che	
  nel	
  metodo	
  
“save”	
  sarà	
  ripreso	
  il	
  contesto	
  dell’applicazione,	
  poi	
  verranno	
  letti	
  i	
  valori	
  dei	
  singoli	
  campi	
  di	
  testo	
  e	
  
associati	
  alla	
  classe	
  “Photo”	
  e	
  solo	
  alla	
  fine	
  saranno	
  salvati	
  nella	
  tabella.	
  

	
  Nel	
   metodo	
   “cancel”	
   invece	
   sarà	
   recuperato	
   il	
   contesto	
   come	
   nel	
   primo	
   caso,	
   ma	
   al	
   contrario,	
   verrà	
  
cancellata	
  quella	
  determinata	
  istanza	
  della	
  classe	
  “Photo”	
  attraverso	
  il	
  metodo	
  “deleteObject:”.	
  

Mentre	
   per	
   la	
   scelta	
   di	
   foto	
   già	
   memorizzate	
   nell’Iphone,	
   l’utente	
   invocherà	
   il	
   metodo	
  
“photoButtonPressed”	
  che	
  andrà	
  a	
  gestire	
  direttamente	
  la	
  libreria	
  fotografica	
  con	
  l’aiuto	
  del	
  protocollo	
  
UIImagePickerDelegate.	
  

Se	
  invece	
  vorrà	
  scattare	
  una	
  nuova	
  foto,	
  dall’interfaccia	
  grafica	
  dovrà	
  invocare	
  il	
  metodo	
  “cameraClick”	
  
che	
   inizializzerà	
   e	
   aprirà	
   il	
   controller	
   “CameraViewController”,	
   il	
   cui	
   funzionamento	
   sarà	
   coordinato	
  
dalla	
          classe	
          “ImmaginePickerDelegate”	
                    che	
         implementerà	
               il	
        protocollo	
  
“UIImagePickerControllerDelegate”	
  con	
  i	
  relativi	
  metodi	
  stabiliti	
  per	
  la	
  gestione	
  della	
  fotocamera.	
  

	
  

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>//GPS

@class Photo;

@interface AddPhotoViewController : UIViewController<UITextFieldDelegate,
UITextViewDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate,
CLLocationManagerDelegate> {

              Photo *photo;
              UITextField *namePhotoTxt;
              UITextField *latitudePhotoTxt;
              UITextField *longitudePhotoTxt;

       	
                                                                                                                                                       4-­‐47	
  
UITextView *descriptionPhotoTxt;
          UIButton *photoButton;
          UIButton *cameraButton;
          UIViewController *provaView;

          CLLocationManager *locationManager;
          CLLocation *startingPoint;

          //toolbar per le foto
          UISegmentedControl *segmentControl;
          //UIToolbar *toolbar;

}
@property (retain, nonatomic) CLLocationManager *locationManager;
@property (retain, nonatomic) CLLocation *startingPoint;

@property      (nonatomic,retain) Photo *photo;
@property      (nonatomic,retain) IBOutlet UITextField *namePhotoTxt;
@property      (nonatomic,retain) IBOutlet UITextField *latitudePhotoTxt;
@property      (nonatomic,retain) IBOutlet UITextField *longitudePhotoTxt;
@property      (nonatomic,retain) IBOutlet UITextView *descriptionPhotoTxt;
@property      (nonatomic, retain) IBOutlet UIButton *photoButton;
@property      (nonatomic, retain) IBOutlet UIButton *cameraButton;
@property      (nonatomic, retain) UIViewController * provaView;

- (IBAction)photoButtonPressed;
- (IBAction)cameraClick:(id) sender;

@end

#import "AddPhotoViewController.h"
#import "PhotoViewController.h"
#import "CameraViewController.h"
#import "Photo.h"

@implementation AddPhotoViewController

@synthesize photo, namePhotoTxt, latitudePhotoTxt, longitudePhotoTxt,
descriptionPhotoTxt;
@synthesize photoButton, cameraButton;
@synthesize locationManager, startingPoint;

#pragma mark -
#pragma mark lifecycle
- (void)viewDidLoad {
      [super viewDidLoad];
   	
                                                                         4-­‐48	
  
//inizializzazione del GPS
      self.locationManager = [[CLLocationManager alloc] init];
      locationManager.delegate = self;
      locationManager.desiredAccuracy = kCLLocationAccuracyBest;
      self.title=@"Inserisci dettagli";
      //dichiarazione dei bottoni
      UIBarButtonItem *cancelButton =[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self
action:@selector(cancel)];
      UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self
action:@selector(save)];
       //inserisco i bottoni di cancel e salvataggio nel NavController
      self.navigationItem.leftBarButtonItem = cancelButton;
      [cancelButton release];
      self.navigationItem.rightBarButtonItem = saveButton;
      [saveButton release];
      //avvio ricezione segnale GPS
      [locationManager startUpdatingLocation];
      [photoButton setImage:photo.photoThumbnailImage forState:UIControlStateNormal];
 }

- (void)viewWillAppear:(BOOL)animated {
      [super viewWillAppear:animated];
      [photoButton setImage:photo.photoThumbnailImage forState:UIControlStateNormal];

}
- (void)didReceiveMemoryWarning {
   [super didReceiveMemoryWarning];
      }

- (void)viewDidUnload {
            [locationManager stopUpdatingLocation];
}

- (void)dealloc {

          [locationManager release];
          [startingPoint release];
          [photo release];
          [namePhotoTxt release];
          [latitudePhotoTxt release];
          [longitudePhotoTxt release];
          [descriptionPhotoTxt release];
          [photoButton release];
          [cameraButton release];
   	
                                                                            4-­‐49	
  
[super dealloc];
}
#pragma mark -
#pragma mark Button's Method

- (void)cancel {
      [photo.managedObjectContext deleteObject:photo];
      NSError *error = nil;
      if (![photo.managedObjectContext save:&error]) {
             exit(-1); // Fail
      }
      [self dismissModalViewControllerAnimated:YES];
}
- (void)save {
      float latitude = [latitudePhotoTxt.text floatValue];
      float longitude = [longitudePhotoTxt.text floatValue];
      NSNumber *latitudeNumber = [NSNumber numberWithFloat:latitude];
      NSNumber *longitudeNumber = [NSNumber numberWithFloat:longitude]
      //setup valori della classe Photo
      photo.namePhoto = namePhotoTxt.text;
      photo.latitudePhoto = latitudeNumber;
      photo.longitudePhoto = longitudeNumber;
      photo.descriptionPhoto = descriptionPhotoTxt.text;
      NSError *error = nil;
      if (![photo.managedObjectContext save:&error]) {
             NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
             exit(-1);
      }
      [self dismissModalViewControllerAnimated:YES];
}
-(IBAction)cameraClick: (id)sender {

     CameraViewController *cameraViewController = [[CameraViewController alloc]
initWithNibName:@"CameraViewController" bundle:[NSBundle mainBundle]];
     UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController: cameraViewController];
     [self.navigationController presentModalViewController:navController animated:YES];
     [cameraViewController release];

     }
#pragma mark -
#pragma mark Photo
- (IBAction)photoButtonPressed {

          [namePhotoTxt endEditing:YES];
          [descriptionPhotoTxt endEditing:YES];
   	
                                                                                 4-­‐50	
  
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
           imagePicker.delegate = self;
           [self presentModalViewController:imagePicker animated:YES];
           [imagePicker release];

}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo {
      NSManagedObject* oldImage = (NSManagedObject *)photo.photoPoint
      if (oldImage != nil) {
             [photo.managedObjectContext deleteObject:oldImage];
      }
      PhotoPoint *image = [NSEntityDescription
insertNewObjectForEntityForName:@"PhotoPoint"inManagedObjectContext:photo.managed
ObjectContext];
      photo.photoPoint = image;
      [image setValue:selectedImage forKey:@"photoPoint"];
      CGSize size = selectedImage.size;
      CGFloat ratio = 0;
      if (size.width > size.height) {
             ratio = 128.0 / size.width;
      }else {
             ratio = 130.0 / size.height;
      }
      CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);
      UIGraphicsBeginImageContext(rect.size);
      [selectedImage drawInRect:rect];
      photo.photoThumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
      [self dismissModalViewControllerAnimated:YES];

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

           [self dismissModalViewControllerAnimated:YES];

}
//disabilita la tastiera quando viene premuto il return
-(BOOL)textFieldShouldReturn:(UITextField *)textField{

           [namePhotoTxt resignFirstResponder];

           return YES;
}
-(BOOL)textViewShouldEndEditing:(UITextView *)textView{
 [descriptionPhotoTxt resignFirstResponder];
    	
                                                                                      4-­‐51	
  
return YES;
}
#pragma mark -
#pragma mark CLLocationManagerDelegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation
              fromLocation:(CLLocation *)oldLocation {
      //inizializzazione
      if (startingPoint == nil) self.startingPoint = newLocation;
      NSString *latitudeStr = [[NSString alloc] initWithFormat:@"%g ",
newLocation.coordinate.latitude];
      latitudePhotoTxt.text = latitudeStr;
      [latitudeStr release];

     NSString *longitudeStr = [[NSString alloc] initWithFormat:@"%g ",
newLocation.coordinate.longitude];
     longitudePhotoTxt.text = longitudeStr;
     [longitudeStr release];
}

- (void)locationManager:(CLLocationManager *)manager
         didFailWithError:(NSError *)error {
      NSString *errorType = (error.code == kCLErrorDenied) ?
      @"Accesso negato" : @"Errore sconosciuto";
      UIAlertView *alert = [[UIAlertView alloc]
                                  initWithTitle:@"Errore nella Localizzazione"
                                  message:errorType
                                  delegate:nil
                                  cancelButtonTitle:@"Okay"
                                  otherButtonTitles:nil];
      [alert show];
      [alert release];
}
@end
Codice	
  11:	
  Interfaccia	
  e	
  implementazione	
  di	
  AddViewController	
  

#import <UIKit/UIKit.h>                                                               #import <Foundation/Foundation.h>
#import "ImmaginePickerDelegate.h"
@interface CameraViewController :                                                     @interface ImmaginePickerDelegate :
UIViewController<UINavigationControllerDelegate>                                      NSObject<UINavigationControllerDeleg
{                                                                                     ate, UIImagePickerControllerDelegate>
     IBOutlet ImmaginePickerDelegate *                                                {
imgPickerDelegate;                                                                          UIImage * selezionaImage;
     IBOutlet UIImageView * vistaImage;
}                                                                                     }
@property (nonatomic, retain)                                                         @property (nonatomic, retain) UIImage

     	
                                                                                                                   4-­‐52	
  
ImmaginePickerDelegate * imgPickerDelegate;          * selezionaImage;
@property (nonatomic, retain) UIImageView *
vistaImage;                                          @end
- (IBAction) clickFoto: (id) sender;                 	
  
@end

	
  
#import "CameraViewController.h"                     #import "ImmaginePickerDelegate.h"
#import "ImmaginePickerDelegate.h"

                                                     @implementation
@implementation CameraViewController                 ImmaginePickerDelegate
@synthesize imgPickerDelegate;
@synthesize vistaImage;                              @synthesize selezionaImage;

#pragma mark -                                       - (void) imagePickerControllerDidCancel:
#pragma mark LifeCycle                               (UIImagePickerController *) picker {
// Implement viewDidLoad to do additional setup            NSLog(@"cancel");
after loading the view, typically from a nib.              [picker.parentViewController
- (void)viewDidLoad {                                dismissModalViewControllerAnimated:Y
   [super viewDidLoad];                              ES];
      //dichiarazione dei bottoni                          [picker release];
      UIBarButtonItem *cancelButton                  }
=[[UIBarButtonItem alloc]                            -
initWithBarButtonSystemItem:UIBarButtonSyste         (void)imagePickerController:(UIImagePi
mItemCancel target:self                              ckerController *) picker
action:@selector(cancel)];                           didFinishPickingMediaWithInfo:(NSDic
      self.navigationItem.leftBarButtonItem =        tionary *) info {
cancelButton;                                              NSLog(@"fisso immagine");
      [cancelButton release];                              self.selezionaImage =
       if(!([UIImagePickerController                 (UIImage*)[info
isSourceTypeAvailable:UIImagePickerControllerSo      objectForKey:UIImagePickerController
urceTypeCamera]))                                    OriginalImage];
      {                                                    [[NSNotificationCenter
      NSLog(@"Fotocamera non presente....uscita      defaultCenter]
dall'applicazione");                                 postNotificationName:@"immagine"
      UIAlertView * erroreAlert = [[UIAlertView      object:nil];
alloc]initWithTitle:@"Errore nella fotocamera "            [picker.parentViewController
message:@"Fotocamera non                             dismissModalViewControllerAnimated:Y
supportata!L'applicazione terminerà." delegate:nil   ES];
cancelButtonTitle:nil otherButtonTitles:@"OK",             [picker release];
nil];                                                }
      [erroreAlert show];                            - (void) dealloc {
      [erroreAlert release];                               [selezionaImage release];
      //warning - terminate is undocumented api            [super dealloc];
      //[[UIApplication sharedApplication]           }
       	
                                                                               4-­‐53	
  
terminate];
     }                                               @end
                                                     	
  
      NSLog(@"Sono in viewDidLoad");
      [[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(cambiaImage)
name:@"immagine" object:nil];
}
- (void)didReceiveMemoryWarning {
      // Releases the view if it doesn't have a
superview.
   [super didReceiveMemoryWarning];

     // Release any cached data, images, etc that
aren't in use.
}

- (void)viewDidUnload {
      // Release any retained subviews of the main
view.
      // e.g. self.myOutlet = nil;
}



- (void)dealloc {
      [super dealloc];
      [vistaImage release];
      [imgPickerDelegate release];
      [ [NSNotificationCenter defaultCenter]
removeObserver:self];




}
- (void) cambiaImage {
      NSLog(@"Immagine cambiata!");
      self.vistaImage.image =
self.imgPickerDelegate.selezionaImage;
}

#pragma mark -
#pragma mark Button's methods
-(void) cancel{
[self dismissModalViewControllerAnimated:YES];
}
   	
                                                       4-­‐54	
  
- (IBAction) clickFoto: (id) sender {
      if(!([UIImagePickerController
isSourceTypeAvailable:UIImagePickerControllerSo
urceTypeCamera]))
      {
      NSLog(@"Fotocamera non presente....uscita
dall'applicazione");
      UIAlertView * erroreAlert = [[UIAlertView
alloc]initWithTitle:@"Errore nella fotocamera "
message:@"Fotocamera non
supportata!L'applicazione terminerà." delegate:nil
cancelButtonTitle:nil otherButtonTitles:@"OK",
nil];
      [erroreAlert show];
      [erroreAlert release];
      //warning - terminate is undocumented api
      //[[UIApplication sharedApplication]
terminate];
      }
      else {
             UIImagePickerController * pickCont =
[[UIImagePickerController alloc] init];
             pickCont.delegate = imgPickerDelegate;
             pickCont.allowsImageEditing = YES;

          pickCont.sourceType =
UIImagePickerControllerSourceTypeCamera;
          [self
presentModalViewController:pickCont
animated:YES];

              }
}

@end
	
  
Codice	
  12:	
  A	
  sinistra:	
  interfaccia	
  e	
  implementazione	
  di	
  CameraViewController.	
  A	
  destra:	
  interfaccia	
  e	
  
implementazione	
  di	
  ImmaginePickerControllerDelegate	
  

4.1.1.2.1.1.2 Interfaccia	
  Grafica	
  
La	
   costruzione	
   della	
   grafica	
   durante	
   la	
   progettazione	
   del	
   controller	
   dovrebbe	
   essere	
   eseguita	
   in	
  
parallelo	
   con	
   la	
   scrittura	
   del	
   codice	
   perché	
   l’Xcode	
   e	
   l’Interface	
   Builder	
   lavorano	
   strettamente	
   in	
  
cooperazione	
   tra	
   loro.	
   Nella	
   creazione	
   di	
   quest’interfaccia,	
   si	
   sono	
   impostati	
   gli	
   elementi	
   grafici	
   e	
   i	
  
collegamenti	
  necessari	
  con	
  il	
  codice	
  tramite	
  l’”Inspector”.	
  

Alcune	
   parti	
   dell’interfaccia,	
   comunque	
   sono	
   state	
   create	
   da	
   codice,	
   come	
   ad	
   esempio,	
   la	
  
configurazione	
   del	
   navigation	
   bar	
   con	
   l’inserimento	
   al	
   suo	
   interno	
   dei	
   pulsanti	
   per	
   il	
   salvataggio	
   e	
  
l’annullamento	
   di	
   azioni	
   invocate	
   dall’utente,	
   oppure	
   dello	
   spazio	
   dedicato	
   alla	
   visualizzazione	
   della	
  

       	
                                                                                                                                                 4-­‐55	
  
foto	
   situato	
   graficamente	
   vicino	
   al	
   pulsante	
   “Scegli	
   foto”,	
   che	
   viene	
   stabilito,	
   nelle	
   sue	
   dimensioni,	
  
attraverso	
  il	
  codice.	
  

	
  




                                                                                                                      	
  
Figura	
  15:	
  Composizione	
  dell'interfaccia	
  di	
  AddViewController	
  

4.1.1.2.1.2 PhotoDetailViewController	
  
E’	
  il	
  controller	
  delegato	
  alla	
  visualizzazione	
  dei	
  dettagli	
  di	
  ciascun	
  punto	
  d’interesse.	
  

Questa	
   maschera	
   sarà	
   richiamata	
   quando	
   l’utente,	
   posizionato	
   sulla	
   form	
   “RootViewController”,	
  
selezionerà	
   un	
   determinato	
   record	
   e	
   conseguentemente	
   al	
   suo	
   tocco,	
   il	
   codice	
   della	
  
“RootViewController”	
  richiamerà	
  le	
  informazioni	
  utili	
  riguardanti	
  quella	
  determinata	
  riga	
  e	
  caricherà	
  i	
  
dati,	
  passando	
  attraverso	
  un’istanza	
  dell’oggetto	
  “Photo”.	
  

Il	
   controller,	
   dovendo	
   quindi	
   visualizzare	
   i	
   dati	
   riguardanti	
   le	
   immagini,	
   dovrà	
   implementare	
   al	
   suo	
  
interno	
  l’UIImagePickerControllerDelegate	
  che	
  permetterà	
  di	
  caricare	
  la	
  foto	
  corrispondente	
  al	
  punto.	
  

4.1.1.2.1.2.1 Funzionamento	
  
Questo	
  controller	
  deriva	
  dalla	
  classe	
  UITableViewController	
  che	
  permetterà	
  di	
  visualizzare	
  i	
  dati	
  sotto	
  
forma	
   di	
   tabelle	
   grafiche	
   e	
   implementerà	
   dei	
   metodi	
   propri	
   per	
   stabilire	
   la	
   loro	
   rappresentazione	
  
grafica.	
  

Il	
  tutto	
  parte	
  dal	
  RootViewController,	
  nel	
  momento	
  in	
  cui	
  l’utente	
  decide	
  di	
  visualizzare	
  i	
  dettagli	
  della	
  
tabella	
  iniziale:	
  il	
  PhotoDetailViewController	
  è	
  inizializzato	
  e	
  gli	
  è	
  passata	
  come	
  parametro	
  un’istanza	
  
dell’oggetto	
  “Photo”,	
  la	
  quale	
  funge	
  da	
  “wrapper”	
  per	
  i	
  dati	
  stessi	
  e	
  che	
  contiene	
  tutte	
  le	
  informazioni	
  
di	
  cui	
  questa	
  form	
  necessita.	
  	
  

A	
   questo	
   punto	
   nell’impostazione	
   della	
   grafica,	
   l’istanza	
   della	
   classe	
   “Photo”	
   è	
   scomposta	
   nelle	
   sue	
  
proprietà	
   e	
   gli	
   appositi	
   campi	
   delle	
   tabelle	
   in	
   essa	
   contenute	
   vengono	
   riempiti	
   con	
   le	
   informazioni	
  
passate	
  dal	
  RootViewController.	
  

#import <UIKit/UIKit.h>
@class Photo;

@interface PhotoDetailViewController : UITableViewController
<UINavigationControllerDelegate, UIImagePickerControllerDelegate>{
     Photo *photo;

       	
                                                                                                                                             4-­‐56	
  
UIButton *photoButton;
}

@property (nonatomic, retain) Photo *photo;
@property (nonatomic, retain) IBOutlet UIButton *photoButton;

- (IBAction)photoButtonPressed;
- (void)updatePhotoButton;
@end
	
  
#import "PhotoDetailViewController.h"
#import "EditingPhotoViewController.h"
#import "PhotoViewController.h"
#import "Photo.h"

@implementation PhotoDetailViewController

@synthesize photoButton, photo;

#pragma mark -
#pragma mark LifeCycle

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];

      self.navigationItem.rightBarButtonItem = self.editButtonItem;
      UIBarButtonItem *cancelButton =[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self
action:@selector(cancel)];
      self.navigationItem.leftBarButtonItem = cancelButton;
      [cancelButton release];
      self.tableView.allowsSelectionDuringEditing = YES;
       }



- (void)didReceiveMemoryWarning {
      // Releases the view if it doesn't have a superview.
   [super didReceiveMemoryWarning];

           // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
      }


    	
                                                                                   4-­‐57	
  
- (void)dealloc {
      [photo release];
      [photoButton release];
   [super dealloc];
}
-(void)cancel{
      [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark -
#pragma mark tableView
- (void)viewWillAppear:(BOOL)animated {
      [super viewWillAppear:animated];
      self.title = photo.namePhoto;
      [photoButton setImage:photo.photoThumbnailImage forState:UIControlStateNormal];
      [self updatePhotoButton];
      [self.tableView reloadData];

}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
      [super setEditing:editing animated:animated];
      [self updatePhotoButton];
}

#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
     return 1;
}

// Customize the number of rows in the table view.

- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
     return 2;

}

// 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) {


    	
                                                                                      4-­‐58	
  
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2
reuseIdentifier:CellIdentifier] autorelease];
     cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
     }
     // Set up the cell
     switch (indexPath.row) {

           case 0:
                cell.textLabel.text = @"Nome:";
                cell.detailTextLabel.text = photo.namePhoto;
                break;

           case 1:
                cell.textLabel.text = @"Coordinate:";

                NSNumber *lat = photo.latitudePhoto;
                NSNumber *longit = photo.longitudePhoto;
                //visualizzazione coordinate nella tabella
                float latFloat = [lat floatValue];
                float longitFloat = [longit floatValue];
                NSString *latStr = [NSString stringWithFormat:@"%.2f ", latFloat];
                NSString *longitStr =[NSString stringWithFormat:@"%.2f",longitFloat];

                NSString *coordinateStr = [NSString stringWithFormat:@" %@ , %@ ",latStr,
longitStr];
                cell.detailTextLabel.text = coordinateStr;
                break;

           case 3:
                cell.textLabel.text = @"Descrizione:";
                cell.detailTextLabel.text = photo.descriptionPhoto;
                break;

           default:

                break;

           }
           return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath {
      if (self.editing) {
      EditingPhotoViewController *editingview = [[EditingPhotoViewController alloc]
initWithNibName:@"EditingPhotoViewController"bundle:[NSBundle mainBundle]];
    	
                                                                                  4-­‐59	
  
editingview.photo = photo;
          [self.navigationController pushViewController:editingview animated:YES];
          [editingview release];
          }
          else {
          [tableView deselectRowAtIndexPath:indexPath animated:YES];
          }

}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
      return UITableViewCellEditingStyleNone;
}

- (BOOL)tableView:(UITableView *)tableView
shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
     return NO;
}

#pragma mark -

#pragma mark Photo

- (IBAction)photoButtonPressed {
      if (self.editing) {
      UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
      imagePicker.delegate = self;
      [self presentModalViewController:imagePicker animated:YES];
      [imagePicker release];
      }
      else {
      PhotoViewController *photoView = [[PhotoViewController alloc] init];
      photoView.photo = photo;
      [self.navigationController pushViewController:photoView animated:YES];
      [photoView release];
      }
}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo {
      NSManagedObject *oldImage = (NSManagedObject *)photo.photoPoint;
      if (oldImage != nil) {
      [photo.managedObjectContext deleteObject:oldImage];
      }
      PhotoPoint *image = [NSEntityDescription
insertNewObjectForEntityForName:@"PhotoPoint"inManagedObjectContext:photo.managed
ObjectContext];
   	
                                                                                4-­‐60	
  
photo.photoPoint = image;
              [image setValue:selectedImage forKey:@"photoPoint"];
              CGSize size = selectedImage.size;
              CGFloat ratio = 0;
              if (size.width > size.height) {
              ratio = 128.0 / size.width;
              } else {
              ratio = 130.0 / size.height;

              }
              CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);
              UIGraphicsBeginImageContext(rect.size);
              [selectedImage drawInRect:rect];
              photo.photoThumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
              [self dismissModalViewControllerAnimated:YES];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
      [self dismissModalViewControllerAnimated:YES];
}

- (void)updatePhotoButton {
      BOOL editing = self.editing;
      if (photo.photoThumbnailImage != nil) {
      photoButton.highlighted = editing;
      }
      else {
      photoButton.enabled = editing;
      }
}
@end	
  
Codice	
  13:Interfaccia	
  e	
  implementazione	
  di	
  PhotoDetailViewController	
  

4.1.1.2.1.2.2 Interfaccia	
  Grafica	
  
La	
   grafica	
   è	
   organizzata,	
   come	
   già	
   scritto,	
   sotto	
   forma	
   di	
   più	
   campi	
   tabellari	
   che	
   elencano	
   i	
   dati	
   del	
  
punto	
   e	
   di	
   un	
   elemento	
   di	
   tipo	
   UIView	
   dove	
   è	
   stato	
   posto	
   un	
   bottone	
   chiamato,	
   “Scegli	
   foto”	
   che	
  
consente,	
   secondo	
   lo	
   stato	
   di	
   “editing”	
   in	
   cui	
   si	
   trova	
   il	
   controller,	
   di	
   associare	
   o	
   visualizzare	
   la	
   foto	
  
presente	
  nella	
  libreria	
  di	
  quel	
  punto.	
  

Nel	
   caso	
   della	
   visualizzazione	
   della	
   foto	
   associata,	
   verrà	
   inizializzato	
   un	
   altro	
   controller,	
   nominato	
  
“PhotoViewController”,	
   mentre	
   nel	
   caso	
   in	
   cui	
   il	
   controller	
   risulti	
   essere	
   in	
   modalità	
   editing,	
   invece,	
  
sarà	
  aperta	
  la	
  libreria	
  fotografica.	
  	
  

	
  

	
  




       	
                                                                                                                                                               4-­‐61	
  
 
Figura	
  16:	
  Rappresentazione	
  dell'interfaccia	
  grafica	
  di	
  PhotoDetailViewController	
  

4.1.1.2.1.3 PhotoViewController	
  
E’	
  la	
  form	
  delegata	
  a	
  rappresentare	
  l’immagine	
  che	
  descrive	
  un	
  punto	
  d’interesse.	
  

Essa	
   è	
   invocata	
   dal	
   “PhotoDetailViewController”	
   il	
   quale	
   la	
   inizializzerà	
   e	
   le	
   assegnerà	
   un	
   determinato	
  
valore	
  alla	
  proprietà	
  di	
  tipo	
  “Photo”.	
  

Graficamente	
   sarà	
   composto	
   da	
   un	
   oggetto	
   grafico	
   UIImageView	
   che	
   sarà	
   impostato	
   attraverso	
  
l’Interface	
  Builder	
  ma	
  la	
  cui	
  immagine	
  sarà	
  dimensionata	
  tramite	
  codice.	
  	
  	
  

4.1.1.2.1.3.1 Funzionamento	
  
Il	
   “PhotoViewController”	
   sarà	
   inizializzato	
   dal	
   PhotoDetailViewController	
   il	
   quale	
   come	
   scritto	
  
imposterà	
  la	
  proprietà	
  di	
  tipo	
  “Photo”.	
  

Da	
   quest’istanza	
   si	
   estrarranno	
   i	
   dati	
   per	
   la	
   visualizzazione	
   dell’immagine	
   e	
   il	
   nome	
   del	
   punto	
   che	
  
servirà	
   ad	
   impostare	
   il	
   titolo	
   del	
   controller	
   visuale	
   e	
   si	
   setteranno	
   i	
   parametri	
   del	
   visualizzatore	
  
d’immagine.	
  

#import <UIKit/UIKit.h>
@class Photo;

@interface PhotoViewController : UIViewController {
     Photo *photo;
     UIImageView *imageView;
}

      	
                                                                                                                                                  4-­‐62	
  
@property (nonatomic, retain) Photo *photo;
@property (nonatomic, retain) UIImageView *imageView;
@end
	
  
#import "PhotoViewController.h"
#import "Photo.h"

@implementation PhotoViewController
@synthesize photo, imageView;
#pragma mark -
#pragma mark lifecycle
- (void)viewDidLoad {
      [super viewDidLoad];
      self.title = photo.namePhoto;
      UIBarButtonItem *cancelButton =[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self
action:@selector(cancel)];
      self.navigationItem.leftBarButtonItem = cancelButton;
      [cancelButton release];
      imageView = [[UIImageView alloc] initWithFrame:[UIScreen
mainScreen].applicationFrame];
      imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleWidth;
      imageView.contentMode = UIViewContentModeScaleAspectFit;
      imageView.backgroundColor = [UIColor whiteColor];
      self.view = imageView;
      imageView.image = [photo.photoPoint valueForKey:@"photoPoint"];
}
- (void)didReceiveMemoryWarning {
      // Releases the view if it doesn't have a superview.
   [super didReceiveMemoryWarning];
      }
- (void)viewDidUnload {
      }
- (void)dealloc {
      [photo release];
      [imageView release];
   [super dealloc];
}
#pragma mark -
#pragma mark Button's methods
-(void) cancel{
      [self.navigationController popViewControllerAnimated:YES];
}
@end	
  
Codice	
  14:Interfaccia	
  e	
  implementazione	
  di	
  PhotoViewController	
  

     	
                                                                             4-­‐63	
  
4.1.1.2.1.4 EditingPhotoViewController	
  
E’	
  il	
  view	
  controller	
  che	
  serve	
  a	
  modificare	
  le	
  informazioni	
  di	
  un	
  determinato	
  punto,	
  in	
  particolare	
  la	
  
parte	
   delle	
   informazioni	
   inerenti	
   al	
   suo	
   nome	
   e	
   alla	
   sua	
   descrizione,	
   poiché	
   i	
   campi	
   riguardanti	
   le	
  
coordinate	
  non	
  possono	
  essere	
  modificati	
  dall’utente.	
  

4.1.1.2.1.4.1 Funzionamento	
  
E’	
   una	
   classe	
   che	
   deriva	
   dall’UIViewController	
   e	
   gestisce	
   direttamente	
   gli	
   eventi	
   scatenati	
   dagli	
   oggetti	
  
di	
   tipo	
   UITextField	
   e	
   UITextView	
   implementando	
   i	
   protocolli	
   UITextFieldDelegate	
   e	
  
UITextViewDelegate.	
  

Sostanzialmente	
   questo	
   controller	
   si	
   occuperà	
   della	
   sostituzione	
   dei	
   dati	
   già	
   presenti	
   nella	
   tabella,	
   dei	
  
campi	
  riguardanti	
  il	
  nome,	
  descrizione	
  e	
  la	
  foto,	
  con	
  nuove	
  informazioni	
  compilate	
  dall’utente.	
  

Il	
   codice	
   quindi	
   recupererà	
   il	
   contesto	
   dell’applicazione,	
   leggerà	
   i	
   campi	
   di	
   testo	
   e	
   assegnerà	
   i	
   loro	
  
valori	
   a	
   un’istanza	
   della	
   classe	
   “Photo”,	
   aggiornando	
   poi	
   quel	
   determinato	
   record	
   della	
   tabella	
   con	
  
l’invocazione	
  del	
  metodo	
  “save”.	
  

#import <UIKit/UIKit.h>
@class Photo;

@interface EditingPhotoViewController : UIViewController<UITextFieldDelegate,
UITextViewDelegate> {
     Photo *photo;
     UITextField *namePhotoTxt;
     UITextField *latitudePhotoTxt;
     UITextField *longitudePhotoTxt;
     UITextView *descriptionPhotoTxt;
}
@property (nonatomic,retain) Photo *photo;
@property (nonatomic,retain) IBOutlet UITextField *namePhotoTxt;
@property (nonatomic,retain) IBOutlet UITextField *latitudePhotoTxt;
@property (nonatomic,retain) IBOutlet UITextField *longitudePhotoTxt;
@property (nonatomic,retain) IBOutlet UITextView *descriptionPhotoTxt;
@end
	
  
#import "EditingPhotoViewController.h"
#import "Photo.h"

@implementation EditingPhotoViewController
@synthesize photo, namePhotoTxt, latitudePhotoTxt, longitudePhotoTxt,
descriptionPhotoTxt;

#pragma mark -
#pragma mark Lifecycle

 // Implement viewDidLoad to do additional setup after loading the view, typically from a
nib.
 - (void)viewDidLoad {
 [super viewDidLoad];

      	
                                                                                                                                                    4-­‐64	
  
self.title = @"Editing foto";
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self
action:@selector(cancel)];
self.navigationItem.leftBarButtonItem = cancelButton;
       [cancelButton release];

UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
initWithTitle:@"Salva"style:UIBarButtonItemStyleDone target:self
action:@selector(save)];
      self.navigationItem.rightBarButtonItem = saveButton;
       [saveButton release];
       self.namePhotoTxt.text = photo.namePhoto;
       NSNumber *lat = photo.latitudePhoto;
       NSNumber *longit = photo.longitudePhoto;
       //visualizzazione coordinate nei textField
       float latFloat = [lat floatValue];
       float longitFloat = [longit floatValue];
       NSString *latStr = [NSString stringWithFormat:@"%.2f ", latFloat];
       NSString *longitStr =[NSString stringWithFormat:@"%.2f",longitFloat];
       self.latitudePhotoTxt.text = latStr;
       self.longitudePhotoTxt.text = longitStr;
       self.descriptionPhotoTxt.text = photo.descriptionPhoto;

 }
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
 [namePhotoTxt resignFirstResponder];
      return YES;
}
- (void)didReceiveMemoryWarning {
      // Releases the view if it doesn't have a superview.
   [super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
}



- (void)dealloc {
      [photo release];
      [namePhotoTxt release];
      [latitudePhotoTxt release];
      [longitudePhotoTxt release];
      [descriptionPhotoTxt release];
   [super dealloc];
   	
                                                                          4-­‐65	
  
}



#pragma mark -
#pragma mark Button's Method
-(void)cancel{
      [self.navigationController popViewControllerAnimated:YES];
}

-(void)save{
      float latitude = [latitudePhotoTxt.text floatValue];
      float longitude = [longitudePhotoTxt.text floatValue];
      NSNumber *latitudeNumber = [NSNumber numberWithFloat:latitude];
      NSNumber *longitudeNumber = [NSNumber numberWithFloat:longitude];
             //setup valori della classe Photo
      photo.namePhoto = namePhotoTxt.text;
      photo.latitudePhoto = latitudeNumber;
      photo.longitudePhoto = longitudeNumber;
      photo.descriptionPhoto = descriptionPhotoTxt.text;
      NSError *error = nil;
      if (![photo.managedObjectContext save:&error]) {

                          NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

                 exit(-1); // Fail

            }
            [self.navigationController popViewControllerAnimated:YES];
}
@end
	
  
Codice	
  15:	
  Interfaccia	
  e	
  implementazione	
  di	
  EditingPhotoViewController	
  

4.1.1.2.1.4.2 Interfaccia	
  Grafica	
  
L’interfaccia	
   di	
   questo	
   controller	
   si	
   presenterà	
   composta	
   da	
   un	
   campo	
   di	
   testo	
   modificabile	
   che	
  
rappresenterà	
  il	
  nome	
  del	
  punto	
  d’interesse,	
  seguito	
  poi	
  dalla	
  sua	
  descrizione,	
  anch’essa	
  modificabile	
  e	
  
dai	
  campi	
  di	
  visualizzazione	
  delle	
  coordinate,	
  non	
  modificabili.	
  




     	
                                                                                                                                       4-­‐66	
  
 
Figura	
  17:	
  Interfaccia	
  grafica	
  dell'EditingPhotoViewController	
  

4.1.1.2.1.5 RootViewController	
  
Per	
  quanto	
  concerne	
  il	
  discorso	
  riguardante	
  questo	
  controller,	
  la	
  spiegazione	
  sul	
  suo	
  funzionamento	
  
sarà	
   suddivisa	
   su	
   più	
   capitoli	
   poiché	
   è	
   la	
   base	
   di	
   tutto	
   il	
   funzionamento	
   del	
   progetto	
   e	
   quindi	
  
incorporerà	
  in	
  parte	
  anche	
  le	
  funzionalità	
  degli	
  altri	
  moduli.	
  

In	
   questo	
   paragrafo	
   si	
   tratterà	
   la	
   parte	
   del	
   view	
   controller	
   che	
   gestisce	
   le	
   tabelle	
   del	
   database	
   con	
   i	
  
metodi	
   coinvolti	
   nel	
   caricamento	
   dei	
   dati	
   nell’interfaccia	
   grafica	
   e	
   nella	
   memoria	
   temporanea	
  
necessaria	
  alle	
  successive	
  elaborazioni.	
  	
  

Esso	
   è	
   di	
   tipo	
   UITableViewController	
   poiché	
   le	
   informazioni	
   contenute	
   in	
   memoria,	
   saranno	
  
rappresentate	
   con	
   una	
   grafica	
   simile	
   a	
   una	
   tabella	
   e	
   implementerà	
   il	
   protocollo	
  
“NSFetchedResultsControllerDelegate”	
   che	
   faciliterà	
   il	
   caricamento	
   e	
   l’estrazione	
   dei	
   dati	
   stessi	
   dalla	
  
memoria.	
  

4.1.1.2.1.5.1 Funzionamento	
  
Quando	
  è	
  caricata	
  la	
  maschera	
  “RootViewController”,	
  sono	
  inizializzati	
  sia	
  il	
  contesto	
  dell’applicazione	
  
sia	
  gli	
  altri	
  parametri	
  necessari	
  all’iterazione	
  con	
  il	
  database	
  creato	
  inizialmente.	
  

Bisogna	
   evidenziare	
   che	
   ogni	
   volta	
   che	
   ci	
   sarà	
   un’iterazione	
   con	
   i	
   dati	
   memorizzati	
   in	
   tabella,	
   sarà	
  
inizializzata	
   e	
   usata	
   un’istanza	
   dell’oggetto	
   NSFetchedResultsController,	
   che	
   sarà	
   ottenuta	
   andando	
  
dapprima	
  a	
  impostare	
  un	
  sort	
  descriptor	
  sulla	
  fetch	
  request.	
  

Quando	
   in	
   sostanza	
   sarà	
   richiesto	
   il	
   caricamento	
   di	
   questa	
   form,	
   nel	
   metodo	
   “ViewDidLoad”	
   verrà	
  
richiamato	
   il	
   metodo	
   fetchedResultsController	
   che	
   restituirà	
   un	
   oggetto	
   di	
   tipo	
  
NSFetchedResultsController,	
  il	
  quale	
  invocherà	
  il	
  metodo	
  performFetch	
  che	
  ritornerà	
  una	
  prima	
  serie	
  
di	
  dati	
  .	
  

- (void)viewDidLoad {

      	
                                                                                                                                                             4-­‐67	
  
NSError *error;
     if (![[self fetchedResultsController] performFetch:&error]) {
            // Update to handle the error appropriately.         NSLog(@"Unresolved
error %@, %@", error, [error userInfo]);
            exit(-1); // Fail
}

}	
  
- (NSFetchedResultsController *)fetchedResultsController {

  if (fetchedResultsController != nil) {
     return fetchedResultsController;
  }

  /*
      Set up the fetched results controller.
     */
     // Create the fetch request for the entity.
     NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
     // Edit the entity name as appropriate.
     NSEntityDescription *entity = [NSEntityDescription entityForName:@"Photo"
inManagedObjectContext:managedObjectContext];
     [fetchRequest setEntity:entity];
     // Set the batch size to a suitable number.
     [fetchRequest setFetchBatchSize:20];

     // Edit the sort key as appropriate.
     NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"namePhoto" ascending:NO];
     NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

      [fetchRequest setSortDescriptors:sortDescriptors];
      // Edit the section name key path and cache name if appropriate.
   // nil for section name key path means "no sections".
      NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext sectionNameKeyPath:nil
cacheName:@"Root"];
   aFetchedResultsController.delegate = self;
      self.fetchedResultsController = aFetchedResultsController;
      [aFetchedResultsController release];
      [fetchRequest release];
      [sortDescriptor release];
      [sortDescriptors release];
      return fetchedResultsController;
}

   	
                                                                                 4-­‐68	
  
            	
  

A	
   questo	
   punto	
   saranno	
   richiamati	
   per	
   l’aggiornamento,	
   i	
   metodi	
   numberOfRowsInSection	
   e	
  
cellForRowAtIndexPath,	
  come	
  mostrato	
  nel	
  seguente	
  pezzo	
  di	
  codice.	
  

- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections]
objectAtIndex:section];
     return [sectionInfo numberOfObjects];
}
	
  
- (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] autorelease];
  }

               Photo *photo = [fetchedResultsController objectAtIndexPath:indexPath];
               TagPoint *tag = [[TagPoint alloc]init];



               cell.textLabel.text = photo.namePhoto;
               if ((photo.namePhoto)!=nil) {
                           [memory addObject: photo];//photo.namePhoto
                           [tag setNamePoint:photo.namePhoto];
                           [tag setDescriptPoint:photo.descriptionPhoto];
                           [tag setLatPoint:photo.latitudePhoto];
                           [tag setLongitPoint:photo.longitudePhoto];

                            [memoryTag addObject:tag];
               }
                }
       return cell;
}
	
  
	
  

Quest’ultimo	
  metodo	
  configurerà	
  ogni	
  cella	
  della	
  table	
  view,	
  creerà	
  un’istanza	
  della	
  classe	
  Photo	
  e	
  la	
  
assocerà	
   al	
   corrispettivo	
   fetchedResultsController	
   cosicché	
   si	
   estrarrà	
   dall’istanza	
   appena	
   creata	
   le	
  
proprietà	
   che	
   si	
   vorranno	
   visualizzare	
   nella	
   schermata	
   (in	
   questo	
   caso	
   il	
   nome	
   del	
   punto)	
   e	
   si	
  
assegneranno	
  i	
  valori	
  alle	
  altre	
  proprietà	
  dell’oggetto	
  “Photo”;	
  aggiungendo	
  alla	
  fine	
  del	
  metodo	
  ogni	
  
istanza	
  della	
  classe	
  “Photo”	
  ad	
  un	
  array	
  per	
  la	
  memorizzazione	
  globale	
  dei	
  singoli	
  punti.	
  
        	
                                                                                                                                           4-­‐69	
  
Un	
  utente,	
  quindi,	
  dall’elenco	
  iniziale,	
  potrà	
  vedere	
  in	
  dettaglio	
  un	
  record	
  ben	
  preciso	
  grazie	
  al	
  metodo	
  
didSelectRowAtIndexPath	
   che	
   permetterà	
   di	
   estrarre	
   tramite	
   il	
   fetchedResultsController	
   e	
  
l’invocazione	
   del	
   metodo	
   objectatindexpath,	
   un	
   oggetto	
   del	
   tipo	
   “Photo”	
   il	
   cui	
   valore	
   imposterà	
   la	
  
proprietà	
   di	
   tipo	
   “Photo”	
   della	
   classe	
   PhotoDetailViewController	
   che	
   servirà	
   a	
   visualizzare	
   i	
   dati	
  
relativi	
  a	
  quel	
  determinato	
  record.	
  

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath {

   // Navigation logic may go here -- for example, create and push another view controller.
      PhotoDetailViewController *photoDetailView = [[PhotoDetailViewController alloc]
initWithNibName:@"PhotoDetailViewController"bundle:[NSBundle mainBundle]];
      Photo *photo = (Photo *)[fetchedResultsController objectAtIndexPath:indexPath];
      photoDetailView.photo = photo;
      //NSLog(@"sono in didSelectRowAtIndexPath...");

              [self.navigationController pushViewController:photoDetailView animated:YES];
              memoryTag = [[NSMutableArray alloc]init];
              memory =[[NSMutableArray alloc]init];
              POIs = [[NSMutableArray alloc]init];
              [self.tableView reloadData];

}
	
  
	
  

Se	
   le	
   informazioni	
   saranno	
   cambiate,	
   ad	
   esempio	
   quando	
   l’utente	
   aggiungerà	
   dei	
   punti,	
   oppure	
   li	
  
toglierà,	
  allora	
  sarà	
  invocato	
  il	
  metodo	
  “controllerDidChangeContent”	
  che	
  aggiornerà	
  la	
  table	
  view.	
  

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
      // In the simplest, most efficient, case, reload the table view.
      [self.tableView reloadData];
}
	
  
	
  

Se	
  invece	
  la	
  vista	
  della	
  tabella	
  sarà	
  impostata	
  in	
  modalità	
  di	
  “editing”,	
  si	
  darà	
  la	
  possibilità	
  all’utente	
  di	
  
modificare	
   i	
   record	
   esistenti,	
   eliminandone	
   quelli	
   scelti:	
   se	
   ciò	
   accadrà,	
   quindi,	
   significherà	
   che	
   sarà	
  
stato	
  invocato	
  il	
  metodo	
  “commitEditingStyle”.	
  	
  

Esso	
  recupererà	
  il	
  contesto	
  attraverso	
  il	
  “fetchedResultsController”	
  	
  che	
  poi	
  in	
  un	
  secondo	
  momento,	
  
tramite	
   il	
   metodo	
   “deleteObject”	
   contenuto	
   in	
   esso,	
   permetterà	
   di	
   cancellare	
   dal	
   database	
   quel	
  
determinato	
   dato,	
   salvando	
   poi	
   il	
   contesto	
   ad	
   azione	
   terminata	
   e	
   re-­‐invocando	
   il	
   metodo	
   viewDidLoad	
  
per	
  l’aggiornamento	
  dell’interfaccia	
  grafica.	
  	
  

- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
     if (editingStyle == UITableViewCellEditingStyleDelete) {
      // Delete the managed object for the given index path
            NSManagedObjectContext *context = [fetchedResultsController
       	
                                                                                                                                                   4-­‐70	
  
managedObjectContext];
          [context deleteObject:[fetchedResultsController
objectAtIndexPath:indexPath]];

                       // Save the context.
                       NSError *error = nil;
                       if (![context save:&error]) {

                                 NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                                 abort();
                       }
                       [self viewDidLoad];
              }
}
	
  
	
  

4.1.2 Implementazione	
  dell’Augmented	
  Reality	
  (ARKit)	
  
La	
   base	
   di	
   questo	
   sistema	
   è	
   la	
   libreria	
   rilasciata	
   dall’iPhoneDevCamp,	
   l’ARKit,	
   che	
   ha	
   permesso	
   lo	
  
sviluppo	
   di	
   molteplici	
   applicativi	
   per	
   l’uso	
   della	
   realtà	
   aumentata,	
   come	
   ad	
   esempio	
   i	
   famosi	
   “Layar”	
   e	
  
“Wikitude”.	
  

Questa	
   libreria	
   è	
   stata	
   usata	
   su	
   molti	
   applicativi	
   di	
   questo	
   tipo	
   perché	
   fornisce	
   un	
   utilizzo	
   intuitivo,	
  
almeno	
   per	
   quanto	
   concerne	
   lo	
   sviluppo	
   di	
   moduli	
   di	
   applicazioni	
   elementari	
   e	
   consente	
   allo	
   stesso	
  
tempo	
  un	
  continuo	
  miglioramento	
  del	
  codice	
  da	
  parte	
  di	
  programmatori	
  esterni	
  al	
  gruppo	
  di	
  sviluppo,	
  
grazie	
  alla	
  disponibilità	
  del	
  suo	
  codice.	
  

Per	
   iniziare	
   a	
   capire	
   il	
   funzionamento	
   è	
   necessario	
   seguire	
   le	
   poche	
   indicazioni	
   disponibili	
   sulla	
   sua	
  
struttura	
   logica	
   e	
   sul	
   modo	
   di	
   interagire	
   con	
   l’interfaccia	
   grafica,	
   poi,	
   il	
   programmatore	
   avrà	
   la	
  
possibilità	
  di	
  ottenere	
  un	
  sistema	
  estremamente	
  dinamico	
  nel	
  suo	
  funzionamento.	
  

Per	
  realizzare	
  questa	
  parte	
  del	
  progetto,	
  si	
  potevano	
  seguire	
  due	
  strade:	
  

              ⇒ Implementare	
  ARKit	
  	
  
              ⇒ Sfruttare	
  le	
  API	
  di	
  Wikitude	
  

La	
   soluzione	
   scelta,	
   è	
   stata	
   quella	
   di	
   usare	
   la	
   libreria	
   ARKit,	
   ovvero	
   la	
   madre	
   delle	
   API	
   di	
   Wikitude,	
  
perché	
  presentava,	
  rispetto	
  alla	
  seconda	
  scelta,	
  	
  meno	
  vincoli	
  per	
  lo	
  sviluppo	
  di	
  un	
  programma.	
  	
  

La	
   caratteristica	
   fondamentale	
   di	
   questa	
   libreria	
   è	
   la	
   suddivisione	
   del	
   suo	
   funzionamento	
   in	
   due	
  
moduli	
  distinti	
  :	
  

              •    Il	
  primo	
  usato	
  per	
  l’elaborazione	
  dei	
  punti	
  d’interesse	
  presi	
  in	
  ingresso	
  dal	
  sistema;	
  
              •    Il	
   secondo	
   sviluppato	
   per	
   l’analisi	
   automatica	
   dei	
   dati	
   (compresa	
   l’iterazione	
   fra	
   i	
   sensori	
   del	
  
                   telefono	
  e	
  i	
  punti	
  d’interesse).	
  

	
  
	
  




       	
                                                                                                                                                           4-­‐71	
  
 
Figura	
  18:	
  Schema	
  a	
  blocchi	
  del	
  funzionamento	
  dell'implementazione	
  dell'ARKit	
  

4.1.2.1 Funzionamento	
  dell’ARKit	
  
Per	
  semplificare	
  la	
  spiegazione,	
  si	
  partirà	
  con	
  la	
  trattazione	
  generica	
  sul	
  come	
  sono	
  caricati	
  i	
  dati	
  da	
  
elaborare.	
  

In	
   linea	
   generica,	
   i	
   punti	
   per	
   essere	
   disponibili,	
   dovranno	
   essere	
   memorizzati	
   in	
   un	
   array	
  che	
   conterrà	
  
un’istanza	
   dell’oggetto	
   “ARGeoCoordinate”	
   il	
   quale	
   verrà	
   inizializzato	
   con	
   un	
   oggetto	
   del	
   tipo	
  
CLLocation.	
  	
  

L’istanza	
  di	
  questa	
  classe,	
  invece	
  sarà	
  inizializzata	
  tramite	
  i	
  seguenti	
  metodi:	
  

         •   initWithCoordinate:	
  
         •   altitude:	
  
         •   horizontalAccuracy:	
  
         •   verticalAccuracy:	
  
         •   	
  timestamp:	
  

Il	
   primo	
   accetterà	
   i	
   dati	
   contenuti	
   in	
   una	
   “structure”	
   chiamata	
   “CLLocationCoordinate2D”	
   che	
  
memorizzerà	
   la	
   latitudine	
   e	
   la	
   longitudine,	
   espresse	
   nel	
   sistema	
   WGS84;	
   mentre	
   gli	
   altri	
   metodi	
  
serviranno	
   a	
   impostare	
   i	
   valori	
   di	
   altitudine,	
   accuratezza	
   delle	
   misure	
   piane	
   e	
   verticali	
   e	
   il	
   periodo	
  
temporale	
  di	
  misura.	
  

Il	
   riempimento	
   dell’array	
   con	
   i	
   dati	
   voluti,	
   sarà	
   eseguito	
   tramite	
   un	
   metodo	
   inserito	
   nel	
  
RootViewController	
   chiamato	
   “completeArrayOfPOI”	
   che	
   restituirà	
   l’array	
   con	
   gli	
   elementi	
  
memorizzati.	
  

Quest’ultimo	
  sarà	
  invocato	
  quando	
  l’utente	
  richiamerà	
  la	
  visualizzazione	
  dei	
  punti	
  d’interesse,	
  tramite	
  
la	
   libreria	
   dell’Augmented	
   Reality	
   nel	
   metodo	
   “viewArController”.	
   Quando	
   tutti	
   i	
   punti	
   della	
   tabella	
  
saranno	
  memorizzati	
  nell’array,	
  sarà	
  inizializzato	
  il	
  controller	
  ARGeoViewController	
  assieme	
  alle	
  sue	
  
proprietà	
  che	
  saranno	
  impostate	
  con	
  valori	
  adeguati.	
  Per	
  poterlo	
  utilizzare,	
  la	
  classe	
  che	
  lo	
  invocherà,	
  
dovrà	
  implementare	
  il	
  protocollo	
  ”ARViewDelegate”,	
  impostando	
  la	
  sua	
  proprietà	
  di	
  ”delegate”.	
  

- (NSMutableArray *)completeArrayOfPOI
{
     NSMutableArray *temp = [[NSMutableArray alloc]init];

       CLLocation *tempLocation;
       ARGeoCoordinate *tempCoordinate;
       CLLocationCoordinate2D location;
       NSEnumerator *enumerator = [memory objectEnumerator];
    id obj;
          while ( obj = [enumerator nextObject] ) {

                   Photo *p= [[Photo alloc]init];
      	
                                                                                                                                                    4-­‐72	
  
p = obj;
                    NSString *name = p.namePhoto;
                    NSNumber *lat = p.latitudePhoto;
                    NSNumber *longit = p.longitudePhoto;
                    float latFloat = [lat floatValue];
                    float longitFloat = [longit floatValue];

                    location.latitude = latFloat;
                    location.longitude = longitFloat;

           tempLocation = [[CLLocation alloc] initWithCoordinate:location altitude:100.0
horizontalAccuracy:1.0 verticalAccuracy:1.0 timestamp:[NSDate date]];
           tempCoordinate = [ARGeoCoordinate coordinateWithLocation:tempLocation];
           tempCoordinate.title = name;
           [temp addObject:tempCoordinate];
           [tempLocation release];

    }
                    return temp;
}

-(void) viewArController{
      self.locationManager = [[CLLocationManager alloc] init];
      locationManager.delegate = self;
      BOOL headingAvailable = [locationManager headingAvailable];
      if (headingAvailable==NO) {
            UIAlertView * erroreAlert = [[UIAlertView alloc]initWithTitle:@"Errore nella
bussola " message:@"Bussola non supportata!L'applicazione terminerà." delegate:nil
cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
            [erroreAlert show];
            [erroreAlert release];
            exit(1);
      }

               ARGeoViewController *viewController = [[ARGeoViewController alloc] init];
               viewController.debugMode = NO;//YES;

               viewController.delegate = self;

               viewController.scaleViewsBasedOnDistance = YES;
               viewController.minimumScaleFactor = .5;

               viewController.rotateViewsBasedOnPerspective = YES;

               [viewController addCoordinates:[self completeArrayOfPOI]];


        	
                                                                                 4-­‐73	
  
viewController.centerLocation = newCenter;

             [viewController startListening];

           UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController: viewController];
     [self.navigationController presentModalViewController:navController animated:YES];
     [viewController release];
}

Codice	
  16:	
  I	
  metodi	
  completeArrayOfPOI	
  e	
  viewArController	
  

Il	
   protocollo	
   quindi	
   obbligherà	
   in	
   sostanza	
   una	
   determinata	
   classe	
   a	
   definire	
   il	
   metodo	
  
“viewForCoordinate”	
   che	
   restituirà	
   un	
   oggetto	
   di	
   tipo	
   UIView	
   che	
   sarà	
   utilizzato	
   nella	
  
rappresentazione	
  grafica	
  dei	
  punti	
  memorizzati.	
  

Quest’ultimo	
  metodo	
  come	
  si	
  vede	
  dal	
  codice,	
  accetterà	
  in	
  ingresso	
  un	
  oggetto	
  di	
  tipo	
  “ARCoordinate”	
  
che	
  conterrà	
  i	
  campi,	
  non	
  obbligatori,	
  del	
  nome	
  e	
  di	
  una	
  possibile	
  descrizione	
  del	
  punto	
  inserito	
  e	
  al	
  
suo	
  interno	
  costruirà	
  in	
  maniera	
  precisa	
  ogni	
  rappresentazione	
  grafica	
  dei	
  punti	
  d’interesse,	
  andando	
  
a	
   definire	
   l’area	
   di	
   visualizzazione	
   delle	
   informazioni	
   dei	
   POI	
   e	
   creando	
   tramite	
   codice	
   gli	
   oggetti	
   di	
  
tipo	
  UIView	
  che	
  serviranno	
  a	
  contenere	
  le	
  label	
  (etichette)	
  per	
  la	
  visualizzazione	
  del	
  nome	
  del	
  punto	
  e	
  
l’immagine,	
  con	
  lo	
  scopo	
  di	
  dare	
  una	
  rappresentazione	
  grafica	
  dei	
  singoli	
  punti.	
  

#define BOX_WIDTH 150
#define BOX_HEIGHT 100

//visualizzazione delle informazioni relative a un punto
- (UIView *)viewForCoordinate:(ARCoordinate *)coordinate {

     CGRect theFrame = CGRectMake(0, 0, BOX_WIDTH, BOX_HEIGHT);
     UIView *tempView = [[UIView alloc] initWithFrame:theFrame];
     UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, BOX_WIDTH,
20.0)];
     titleLabel.backgroundColor = [UIColor colorWithWhite:.3 alpha:.8];
     titleLabel.textColor = [UIColor whiteColor];
     titleLabel.textAlignment = UITextAlignmentCenter;
     titleLabel.text = coordinate.title;
     //titleLabel.text = coordinate.subtitle;
     [titleLabel sizeToFit];

      titleLabel.frame = CGRectMake(BOX_WIDTH / 2.0 - titleLabel.frame.size.width / 2.0
- 4.0, 0, titleLabel.frame.size.width + 8.0, titleLabel.frame.size.height + 8.0);

      UIImageView *pointView = [[UIImageView alloc] initWithFrame:CGRectZero];
      pointView.image = [UIImage imageNamed:@"location.png"];
      pointView.frame = CGRectMake((int)(BOX_WIDTH / 2.0 - pointView.image.size.width /
2.0), (int)(BOX_HEIGHT / 2.0 - pointView.image.size.height / 2.0),
pointView.image.size.width, pointView.image.size.height);

      	
                                                                                                                                                     4-­‐74	
  
[tempView addSubview:titleLabel];
              [tempView addSubview:pointView];

              [titleLabel release];
              [pointView release];

              return [tempView autorelease];
}
	
  
Codice	
  17:	
  Il	
  metodo	
  viewForCoordinate	
  

	
  

4.1.2.1.1 Interfaccia	
  Grafica	
  
Per	
  questo	
  modulo	
  del	
  progetto	
  la	
  parte	
  grafica	
  è	
  stata	
  impostata	
  completamente	
  da	
  codice,	
  partendo	
  
dal	
   pulsante	
   situato	
   sulla	
   toolbar	
   nel	
   RootViewController,	
   nominato	
   “System	
   AR”,	
   che	
   consente	
  
all’utente	
  di	
  richiamare	
  i	
  metodi	
  e	
  le	
  classi	
  necessari	
  alla	
  creazione	
  dell’Augmented	
  Reality.	
  

Quando	
   il	
   programma	
   avrà	
   eseguito	
   la	
   calibrazione	
   del	
   ricevitore	
   GPS	
   e	
   impostato	
   le	
   coordinate	
  
dell’utente	
   definite	
   come	
   il	
   punto	
   di	
   riferimento	
   del	
   sistema,	
   aprirà	
   l’ARGeoViewController	
   e	
  
inizializzerà	
   e	
   imposterà	
   la	
   schermata	
   che	
   gestirà	
   la	
   fotocamera	
   visualizzando	
   i	
   punti	
   d’interesse,	
  
muovendoli	
  sullo	
  schermo	
  ad	
  ogni	
  cambiamento	
  di	
  posizione	
  del	
  dispositivo.	
  

4.1.3 L’utilizzo	
  dei	
  web	
  services	
  nell’applicazione	
  
Lo	
  sviluppo	
  di	
  questa	
  parte	
  del	
  programma	
  ha	
  lo	
  scopo	
  di	
  farlo	
  iterare	
  con	
  i	
  servizi	
  già	
  disponibili	
  in	
  
rete	
   per	
   il	
   caricamento	
   in	
   memoria	
   di	
   nuovi	
   dati	
   corrispondenti	
   a	
   punti	
   d’interesse	
   specificati	
   in	
  
database	
   remoti	
   e	
   sono	
   resi	
   disponibili	
   a	
   qualsiasi	
   sviluppatore	
   con	
   o	
   senza	
   la	
   registrazione	
   del	
  
programma	
  che	
  li	
  utilizzerà.	
  	
  

Uno	
  dei	
  problemi	
  di	
  questi	
  servizi,	
  è	
  quello	
  che	
  nella	
  maggior	
  parte	
  dei	
  casi	
  essi	
  non	
  coprono	
  con	
  i	
  loro	
  
dati	
   l’Italia	
   e	
   l’Europa	
   ma	
   solamente	
   l’America	
   e	
   l’Australia,	
   quindi,	
   per	
   testare	
   il	
   programma,	
   si	
   è	
  
dovuto	
  selezionare	
  un	
  insieme	
  di	
  servizi	
  web	
  che	
  coprisse	
  anche	
  il	
  nostro	
  stato.	
  Probabilmente	
  il	
  tutto	
  
è	
  causato,	
  dal	
  fatto	
  che	
  questi	
  ultimi	
  sono	
  stati	
  implementati	
  prima	
  in	
  America,	
  in	
  quanto	
  in	
  Europa	
  si	
  è	
  
avuta	
  una	
  diffusione	
  della	
  rete	
  per	
  un	
  uso	
  pubblico,	
  anche	
  sui	
  dispositivi	
  mobili,	
  solamente	
  negli	
  ultimi	
  
anni.	
  

Per	
   decidere	
   quale	
   web	
   service	
   utilizzare,	
   si	
   sono	
   analizzati	
   quelli	
   che	
   potevano	
   soddisfare	
   le	
  
specifiche	
  del	
  progetto,	
  ovvero	
  che	
  fornissero	
  notizie	
  su	
  punti	
  d’interesse	
  come	
  attività	
  commerciali	
  o	
  
musei	
   e	
   località	
   vicine	
   all’utente;	
   poi	
   si	
   sono	
   lette	
   le	
   documentazioni	
   	
   riguardanti	
   la	
   loro	
  
implementazione,	
   ossia	
   la	
   struttura	
   della	
   richiesta	
   da	
   inviare	
   e	
   della	
   risposta	
   mandata,	
   con	
   lo	
   scopo	
   di	
  
rendere	
  il	
  programma	
  capace	
  di	
  inviare	
  e	
  ricevere	
  i	
  dati	
  richiesti	
  utilizzandoli	
  per	
  i	
  suoi	
  scopi.	
  

I	
   web	
   services	
   presi	
   in	
   considerazione	
   sono	
   stati	
   quelli	
   che,	
   in	
   base	
   alle	
   coordinate	
   espresse	
   in	
  
latitudine	
   e	
   longitudine	
   restituivano	
   i	
   POI	
   vicini	
   all’utente,	
   con	
   annesse	
   le	
   informazioni	
   ad	
   esempio	
   sul	
  
nome	
   del	
   luogo,	
   sulla	
   sua	
   storia,	
   o	
   trattando	
   dati	
   di	
   locali	
   commerciali,	
   il	
   loro	
   nome,	
   le	
   informazioni	
  
utili	
  sulla	
  loro	
  attività.	
  	
  

Quelli	
  in	
  esame	
  sono	
  alla	
  fine	
  risultati	
  essere	
  un	
  ristretto	
  numero,	
  tra	
  i	
  quali:	
  

          •     Yahoo	
  Search	
  Service	
  per	
  la	
  ricerca	
  di	
  attività	
  commerciali	
  	
  
          •     Geonames.org	
  per	
  i	
  punti	
  d’interesse	
  riguardanti	
  località	
  turistiche	
  

Il	
   primo	
   richiede	
   la	
   registrazione	
   gratuita	
   del	
   programma	
   fornendo	
   a	
   Yahoo	
   i	
   dati	
   dello	
   sviluppatore	
   e	
  
il	
   nome	
   del	
   programma	
   sul	
   quale	
   implementare	
   il	
   servizio.	
   Eseguite	
   queste	
   operazioni,	
   il	
   gestore	
  
fornisce	
   una	
   chiave	
   che	
   serve	
   al	
   sistema	
   per	
   l’identificazione	
   del	
   programma	
   che	
   ha	
   richiesto	
   le	
  

       	
                                                                                                                                                        4-­‐75	
  
informazioni,	
  e	
  che	
  sarà	
  inserita	
  nella	
  cosiddetta	
  stringa	
  di	
  richiesta.	
  La	
  motivazione	
  per	
  la	
  quale,	
  dopo	
  
svariate	
   prove,	
   non	
   è	
   stato	
   preso	
   in	
   considerazione	
   è	
   che	
   provandolo	
   con	
   le	
   coordinate	
   di	
   Trieste	
   e	
  
Roma,	
  la	
  risposta	
  rimaneva	
  vuota	
  probabilmente	
  perché	
  per	
  l’Italia	
  non	
  ci	
  sono	
  dati	
  disponibili.	
  	
  

Allora	
   si	
   è	
   deciso	
   d’implementare	
   uno	
   dei	
   web	
   services	
   disponibili	
   sul	
   server	
   di	
   geonames.org	
   e	
   in	
  
particolare	
   quello	
   chiamato	
   “findNearByWikipedia”	
   che	
   utilizza	
   come	
   parametri	
   in	
   ingresso	
   le	
  
coordinate	
   di	
   un	
   punto	
   espresse	
   in	
   latitudine	
   e	
   longitudine	
   e	
   restituisce	
   un	
   documento	
   in	
   formato	
   xml	
  
che	
  contiene	
  le	
  informazioni	
  richieste.	
  

4.1.3.1 Funzionamento	
  
Le	
   operazioni	
   per	
   l’estrazione	
   delle	
   informazioni	
   dei	
   punti	
   d’interesse	
   dal	
   web	
   service	
   sono	
   relegate	
  
alla	
  classe	
  NSXmlParser	
  che	
  si	
  occupa	
  del	
  parsing	
  del	
  messaggio	
  xml	
   prelevando	
  i	
  dati	
  utili	
  dai	
  tag	
  del	
  
messaggio.	
  

In	
   questo	
   progetto	
   si	
   richiede	
   l’esecuzione	
   di	
   queste	
   operazioni	
   due	
   volte:	
   durante	
   l’aperturai	
   della	
  
mappa	
   dove	
   si	
   localizzano	
   i	
   pin	
   dei	
   punti	
   d’interesse	
   inseriti	
   dall’utente	
   e	
   quelli	
   caricati	
   tramite	
   il	
   web	
  
service	
  e	
  quando	
  l’utente	
  richiede	
  la	
  form	
  in	
  cui	
  è	
  implementata	
  l’Augmented	
  Reality.	
  

Prima	
  di	
  iniziare	
  a	
  parlare	
  del	
  modo	
  in	
  cui	
  opera	
  il	
  metodo	
  “viewMap”	
  delegato	
  al	
  caricamento	
  dei	
  dati	
  
e	
  alla	
  visualizzazione	
  della	
  mappa,	
  è	
  necessario	
  sapere	
  com’è	
  costituito	
  il	
  sistema.	
  

4.1.3.1.1 Struttura	
  della	
  request	
  e	
  del	
  messaggio	
  di	
  response	
  del	
  web	
  service	
  
Per	
   riuscire	
   a	
   interagire	
   con	
   il	
   web	
   service	
   scelto,	
   si	
   è	
   dovuto	
   leggere	
   la	
   parte	
   descrittiva	
   del	
  
documento	
   riguardante	
   il	
   servizio	
   scelto	
   all’indirizzo	
   http://www.geonames.org/export/web-­
services.html	
   dove	
   è	
   esposta	
   una	
   breve	
   rappresentazione	
   della	
   funzionalità	
   dei	
   servizi	
   disponibili,	
  
come	
   ad	
   esempio	
   i	
   parametri	
   accettati	
   nella	
   stringa	
   di	
   “request”	
   e	
   gli	
   elementi	
   ritornati	
   nella	
  
“response”.	
  




                                                                                                                                                                              	
  
Figura	
  19:	
  Descrizione	
  del	
  web	
  service	
  

Per	
   capire	
   com’è	
   composta	
   la	
   response,	
   si	
   dovrà	
   cliccare	
   sull’esempio	
   di	
   richiesta	
   e	
   così	
   facendo	
  
comparirà	
  in	
  risposta	
  un	
  documento	
  visualizzato	
  nel	
  browser	
  in	
  formato	
  xml,	
  che	
  sarà	
  costituito,	
  come	
  
scritto	
  in	
  precedenza	
  da	
  svariati	
  “tag”	
  ciascuno	
  dei	
  quali	
  descriverà	
  un	
  particolare	
  elemento.	
  




      	
                                                                                                                                                             4-­‐76	
  
 
Figura	
  20:	
  documento	
  xml	
  restituito	
  dal	
  web	
  service	
  

	
  

4.1.3.1.2 Comunicazione	
  fra	
  i	
  controller	
  
Per	
   permettere	
   il	
   passaggio	
   di	
   parametri	
   tra	
   il	
   controller	
   principale	
   e	
   quello	
   delegato	
   alla	
  
visualizzazione	
  dei	
  punti	
  sulla	
  mappa,	
  si	
  sono	
  costruite	
  due	
  classi,	
  chiamate	
  rispettivamente	
  TagPoint	
  
e	
  POIStore.	
  

La	
  prima	
  fornisce	
  l’identificazione	
  di	
  ciascun	
  punto	
  d’interesse,	
  in	
  altre	
  parole,	
  quando	
  si	
  dovrà	
  parlare	
  
dei	
   singoli	
   punti,	
   si	
   dovrà	
   considerare	
   un’istanza	
   della	
   classe	
   “TagPoint”	
   che	
   conterrà	
   al	
   suo	
   interno	
   la	
  
descrizione	
  intera	
  dell’oggetto	
  contenendo	
  le	
  proprietà	
  relative	
  al	
  suo	
  nome,	
  alla	
  sua	
  descrizione,	
  alle	
  
sua	
  latitudine	
  e	
  longitudine.	
  	
  

Mentre	
   per	
   quanto	
   riguarda	
   la	
   seconda	
   classe,	
   essa	
   avrà	
   il	
   compito	
   di	
   inizializzare	
   e	
   contenere	
   in	
  
definita	
  l’array	
  che	
  servirà	
  a	
  memorizzare	
  l’insieme	
  d’istanze	
  di	
  oggetti	
  di	
  tipo	
  “TagPoint”	
  e	
  che	
  verrà	
  
poi	
   utilizzata	
   per	
   l’estrazione	
   dei	
   singoli	
   punti	
   dal	
   controller	
   chiamato	
   “TagViewController”,	
   di	
   cui	
   si	
  
esaminerà	
  il	
  funzionamento	
  nei	
  capitoli	
  successivi.	
  




                                                                                                                                          	
  
Figura	
  21:	
  Passaggio	
  di	
  parametri	
  tra	
  i	
  due	
  view	
  controller	
  



       	
                                                                                                                                                      4-­‐77	
  
#import <Foundation/Foundation.h>            #import "TagPoint.h"

@interface TagPoint : NSObject {             @implementation TagPoint
     @private NSString *namePoint;           @synthesize namePoint, descriptPoint,
     @private NSString *descriptPoint;       urlWiki, latPoint, longitPoint;
     @private NSNumber *latPoint;            -(id)init
     @private NSNumber *longitPoint;         {     namePoint = [[NSString alloc] init];
                                                   descriptPoint =[[NSString alloc]init];
}                                                  latPoint = [[NSNumber alloc] init];
                                                   longitPoint = [[NSNumber alloc] init];
@property (nonatomic,retain)   NSString            return self;
*namePoint;                                  }
@property (nonatomic,retain)   NSString      -(void) setLatPoint:(NSNumber *)lat
*descriptPoint;                              {
@property (nonatomic,retain)   NSNumber            latPoint = lat;
*latPoint;                                   }
@property (nonatomic,retain)   NSNumber      -(void) setLongitPoint:(NSNumber *)longit
*longitPoint;                                {
                                                   longitPoint = longit;
-(id)init;                                   }
-(void) setLatPoint:(NSNumber *)lat;         -(void) setNamePoint:(NSString *) name
-(void) setLongitPoint:(NSNumber *)longit;   {
-(void) setNamePoint:(NSString *) name;            namePoint = name;
-(void) setDescriptionPoint:(NSString        }
*)descript;                                  -(void) setDescriptionPoint:(NSString
-(NSString *) getNamePoint;                  *)descript
-(NSString *) getDescriptionPoint;           {
-(NSNumber *) getLatPoint;                         descriptPoint = descript;
-(NSNumber *) getLongitPoint;                }
                                             -(NSString *) getNamePoint
@end	
                                       {
                                                   return namePoint;
                                             }
                                             -(NSString *) getDescriptionPoint
                                             {
                                                   return descriptPoint;
                                             }
                                             -(NSNumber *) getLatPoint
                                             {
                                                   return latPoint;
                                             }
                                             -(NSNumber *) getLongitPoint
                                             {
                                                   return longitPoint;
                                             }
                                             @end	
  
    	
                                                                                  4-­‐78	
  
#import <Foundation/Foundation.h>                                                  #import "POIStore.h"
                                                                                   #import "TagPoint.h"
@class TagPoint;
@interface POIStore: NSObject {                                                    @implementation POIStore
       @private NSMutableArray *photos;
}                                                                                  @synthesize photos;
@property(nonatomic, retain)
NSMutableArray *photos;                                                            - (id) init
- (id) init;                                                                       {
- (void) setPOI:(NSMutableArray *)array;                                              self = [super init];
- (NSMutableArray *)getPOI;                                                           photos = [[NSMutableArray alloc]init];
@end	
                                                                                return self;
                                                                                   }
                                                                                   - (NSMutableArray *) getPOI
                                                                                   {
                                                                                          return photos;
                                                                                          }

                                                                                   -(void)setPOI: (NSMutableArray *)array
                                                                                   {
                                                                                         photos = array;
                                                                                   }
                                                                                   - (void) dealloc
                                                                                   {
                                                                                         [photos release];
                                                                                         [super dealloc];
                                                                                   }
                                                                                   @end	
  
Codice	
  18:	
  Interfacce	
  e	
  implementazioni	
  delle	
  classi	
  TagPoint	
  e	
  POIStore	
  

Quando	
  poi,	
  saranno	
  passati	
  questi	
  parametri	
  al	
  TagViewController,	
  ossia	
  il	
  controller	
  incaricato	
  alla	
  
visualizzazione	
   della	
   mappa,	
   sarà	
   eseguito	
   il	
   procedimento	
   inverso,	
   ovvero	
   la	
   classe	
   estrarrà	
  
dall’istanza	
  dell’oggetto	
  “POIStore”	
  l’array	
  delle	
  istanze	
  di	
  “TagPoint”	
  che	
  conterranno	
  le	
  informazioni	
  
relative	
  ad	
  ogni	
  singolo	
  punto.	
  	
  

Per	
   quanto	
   concerne	
   il	
   secondo	
   uso	
   di	
   questi	
   dati,	
   ovvero	
   quando	
   l’utente	
   invocherà	
   la	
   realtà	
  
aumentata,	
  si	
  eseguirà	
  lo	
  stesso	
  procedimento	
  spiegato	
  precedentemente	
  per	
  il	
  caricamento	
  dei	
  punti	
  
sulla	
  mappa,	
  con	
  la	
  differenza	
  che	
  in	
  questo	
  caso	
  i	
  dati	
  verranno	
  caricati	
  nell’ARGeoViewController.	
  

	
  

4.1.3.2 Visualizzazione	
  e	
  distribuzione	
  dei	
  punti	
  d’interesse	
  su	
  una	
  mappa	
  	
  
In	
  questo	
  capitolo	
  si	
  tratterà	
  il	
  discorso	
  della	
  visualizzazione	
  di	
  una	
  mappa	
  con	
  la	
  distribuzione,	
  su	
  di	
  
essa,	
  dei	
  punti	
  d’interesse.	
  

I	
  dati,	
  come	
  nel	
  precedente	
  caso,	
  una	
  volta	
  individuati	
  sono	
  memorizzati	
  in	
  un	
  array	
  che	
  servirà	
  a	
  far	
  
passare	
  le	
  informazioni	
  da	
  un	
  controller	
  all’altro.	
  

I	
   dati	
   memorizzati	
   quindi	
   serviranno	
   sia	
   a	
   localizzare	
   i	
   punti	
   sulla	
   mappa,	
   attraverso	
   la	
   latitudine	
   e	
  
longitudine,	
  identificandoli	
  tramite	
  un	
  pin,	
  sia	
  a	
  contenere	
  le	
  informazioni	
  necessarie	
  a	
  descriverli.	
  

       	
                                                                                                                                                   4-­‐79	
  
Sostanzialmente	
   ogni	
   qualvolta	
   l’utente	
   invocherà	
   la	
   sua	
   visualizzazione,	
   esso	
   caricherà	
   la	
   mappa	
   e	
  
inizializzerà	
  l’array	
  con	
  i	
  punti	
  disponibili	
  nella	
  memoria	
  locale	
  e	
  con	
  quelli	
  scaricati	
  dal	
  web	
  service.	
  	
  

4.1.3.2.1 Funzionamento	
  
Il	
   controller	
   che	
   è	
   richiamato	
   dal	
   “RootViewController”	
   per	
   la	
   visualizzazione	
   della	
   mappa	
   è	
   il	
  
“TagViewController”	
  che	
  controlla	
  direttamente	
  la	
  mappa	
  attraverso	
  l’implementazione	
  del	
  protocollo	
  
“MKMapViewDelegate”	
  e	
  l’inclusione	
  nella	
  classe	
  del	
  frame	
  work	
  MapKit.	
  

In	
   esso	
   sono	
   inserite	
   le	
   proprietà	
   per	
   la	
   memorizzazione	
   dell’array	
   dei	
   punti,	
   l’oggetto	
   grafico	
   per	
  
caricare	
  la	
  mappa	
  e	
  due	
  classi	
  chiamate	
  “TouchView”	
  e	
  “MoreInfoView”	
  derivanti	
  dalla	
  classe	
  UIView	
  
per	
  la	
  visualizzazione	
  dei	
  punti	
  nella	
  mappa.	
  

Il	
  sistema	
  quindi	
  sarà	
  così	
  composto:	
  

         ⇒ Dal	
  controller	
  principale	
  TagViewController;	
  
         ⇒ Dalla	
  classe	
  MyAnnotation;	
  
         ⇒ Dalle	
  due	
  classi	
  MoreInfoView	
  e	
  TouchView.	
  

Il	
   primo	
   è	
   quello	
   che	
   gestisce	
   tutto	
   il	
   sistema	
  di	
  visualizzazione	
  della	
  mappa	
  e	
  coordina	
  le	
  classi	
   che	
  
saranno	
   descritte	
   in	
   seguito,	
   caricando	
   i	
   dati	
   dei	
   punti	
   d’interesse,	
   inizializzando	
   le	
   classi	
   per	
   la	
  
visualizzazione	
  della	
  mappa	
  e	
  quelle	
  delegate	
  all’iterazione	
  con	
  l’interfaccia	
  grafica:	
  

             ⇒ La	
  classe	
  TouchView	
  servirà	
  a	
  capire	
  se	
  l’utente	
  invocherà	
  un	
  evento	
  derivato	
  dalla	
  pressione	
  
               di	
  un	
  pulsante	
  oppure	
  no;	
  
             ⇒ La	
   classe	
   MoreInfoView	
   sarà	
   invocata	
   quando	
   il	
   programma	
   caricherà	
   la	
   form	
   per	
   la	
  
               visualizzazione	
  delle	
  informazioni	
  riguardanti	
  un	
  determinato	
  punto.	
  

Oltre	
   a	
   impostare	
   queste	
   classi,	
   descriverà	
   dei	
   metodi	
   per	
   la	
   gestione	
   degli	
   eventi	
   riguardanti	
  
l’apertura	
   e	
   la	
   chiusura	
   della	
   vista	
   gestita	
   dall’istanza	
   della	
   classe	
   MoreInfoView,	
   chiamati	
  
“showAnnotation”	
   per	
   la	
   visualizzazione	
   delle	
   informazioni	
   del	
   singolo	
   punto	
   d’interesse	
   e	
  
“hideAnnotation”	
  per	
  la	
  sua	
  chiusura.	
  

Per	
   la	
   distribuzione	
   dei	
   “pin	
   ”	
   sulla	
   mappa,	
   nel	
   caricamento	
   della	
   form,	
   sarà	
   richiamato	
   il	
   metodo	
  
appartenente	
   al	
   protocollo	
   MKMapViewDelegate,	
   “viewForAnnotation”,	
   per	
   un	
   numero	
   di	
   volte	
   pari	
   al	
  
numero	
  dei	
  punti	
  d’interesse.	
  

#import            <UIKit/UIKit.h>
#import            <MapKit/MapKit.h>
#import            "TouchView.h"
#import            "MyAnnotation.h"
#import            "MoreInfoView.h"

@class POIStore;
@class TagPoint;

@interface TagViewController : UIViewController<UINavigationControllerDelegate,
MKMapViewDelegate> {
     //memorizzazione dati
     POIStore *poiStore;
     //array dei POI contenuti nell'oggetto POIStore
     NSMutableArray *arr;
     MKMapView *mapView;
     TouchView* touchView;

      	
                                                                                                                                                     4-­‐80	
  
IBOutlet MoreInfoView* moreInfoView;
}
@property(nonatomic, retain) POIStore *poiStore;
@property(nonatomic, retain) NSMutableArray *arr;

@property (nonatomic, retain) MKMapView* mapView;
@property (nonatomic, retain) TouchView* touchView;
@property (retain) IBOutlet MoreInfoView* moreInfoView;
extern NSString *const GMAP_ANNOTATION_SELECTED;

- (id) initWithPOIStore:(POIStore *) poiS;
- (void) showAnnotation:(MyAnnotation*) annotation;
- (void) hideAnnotation;

@end

#import      "TagViewController.h"
#import      "POIStore.h"//wrapper dell'array creato
#import      "TagPoint.h"
#import      "CompactNavigatorAppDelegate.h"

#import "MyAnnotationView.h"

@implementation TagViewController

@synthesize poiStore, arr;

@synthesize mapView, touchView, moreInfoView;

NSString * const GMAP_ANNOTATION_SELECTED = @"gmapselected";

#pragma mark -
#pragma mark Lifecycle

//inizializzazione del view controller
- (id) initWithPOIStore:(POIStore *) poiS
{
   self = [super init];
       arr = [[NSMutableArray alloc]init];
       arr = [poiS getPOI];
   return self;
}
- (void)viewDidLoad {
   [super viewDidLoad];
       UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self
   	
                                                                 4-­‐81	
  
action:@selector(cancel)];
      self.navigationItem.leftBarButtonItem = cancelButton;
      [cancelButton release];
      touchView = [[TouchView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
      touchView.delegate = self;
      touchView.callAtHitTest = @selector(stopFollowLocation);

  mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
     mapView.delegate = self;
  [touchView addSubview:mapView];
  [self.view addSubview:touchView];

     NSMutableArray* annotations = [[NSMutableArray alloc] init];
     NSEnumerator *enumerator = [arr objectEnumerator];
  id obj;

  while ( obj = [enumerator nextObject] ) {
           TagPoint *tag = [[TagPoint alloc] init];
           tag = obj;
           NSString *namePt = [[NSString alloc]init];
           NSString *descrPt = [[NSString alloc] init];
           NSString *linkPt = [[NSString alloc]init];

               NSNumber *lat = tag.latPoint;
               NSNumber *longit = tag.longitPoint;
               namePt = [tag getNamePoint];
               descrPt = [tag getDescriptionPoint];//modificato ora
               linkPt = [tag getURLWiki];
               float latFloat = [lat floatValue];
               float longitFloat = [longit floatValue];

          CLLocationCoordinate2D coord2d = {latFloat,longitFloat};
          MyAnnotation *anno = [[MyAnnotation alloc] initWithCoords:coord2d name:namePt
descr:descrPt link:linkPt ];
          [annotations addObject:anno];
          [anno release];

               }

          [mapView addAnnotations:annotations];

      [annotations release];
      self.moreInfoView.frame = CGRectMake(20.0, 250.0 + 300.0,
self.moreInfoView.frame.size.width, self.moreInfoView.frame.size.height);
      [self.touchView addSubview:self.moreInfoView];
}
   	
                                                                              4-­‐82	
  
#pragma mark -
#pragma mark Map's method
- (void) stopFollowLocation {
      MyAnnotation* annotation;
      for (annotation in mapView.selectedAnnotations) {
            [mapView deselectAnnotation:annotation animated:NO];
      }
      [self hideAnnotation];
}

- (void) annotationClicked: (id <MKAnnotation>) annotation {
      MyAnnotation* ann = (MyAnnotation*) annotation;
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Map Tag View"
message:[NSString stringWithFormat:@"You clicked at annotation: %@",ann.name]
delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
      [alert show];
      [alert release];
}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id
<MKAnnotation>)annotation {
     //NSLog(@"Sono qui...in mapView");
     MKAnnotationView* annotationView = nil;

     MyAnnotation *myAnnotation = (MyAnnotation*) annotation;
     NSString* identifier = @"Pin";
     MKPinAnnotationView* annView = (MKPinAnnotationView*)[self.mapView
dequeueReusableAnnotationViewWithIdentifier:identifier];

     if(nil == annView) {
            annView = [[[MKPinAnnotationView alloc] initWithAnnotation:myAnnotation
reuseIdentifier:identifier] autorelease];
     }

          [annView addObserver:self
                     forKeyPath:@"selected"
                         options:NSKeyValueObservingOptionNew
                         context:GMAP_ANNOTATION_SELECTED];

          [annView setPinColor:MKPinAnnotationColorGreen];

          CGPoint notNear = CGPointMake(10000.0,10000.0);
          annView.calloutOffset = notNear;
          annotationView = annView;

          [annotationView setEnabled:YES];
   	
                                                                                 4-­‐83	
  
[annotationView setCanShowCallout:YES];

           return annotationView;

           }



- (void)observeValueForKeyPath:(NSString *)keyPath
              ofObject:(id)object
                change:(NSDictionary *)change
               context:(void *)context{

    NSString *action = (NSString*)context;
    if([action isEqualToString:GMAP_ANNOTATION_SELECTED]){
             BOOL annotationAppeared = [[change valueForKey:@"new"] boolValue];
             if (annotationAppeared) {
                    [self showAnnotation:((MyAnnotationView*) object).annotation];
             }
             else {

                     [self hideAnnotation];
                }
           }
}

- (void)showAnnotation:(MyAnnotation*)annotation {
           //configurazione dell'UITextView
           self.moreInfoView.descr.editable = NO;//disabilitazione dell'editing
           self.moreInfoView.descr.showsVerticalScrollIndicator = YES;
           self.moreInfoView.descr.font = [UIFont fontWithName:@"Arial" size:10];

          self.moreInfoView.text.text = annotation.title;
          self.moreInfoView.descr.text = annotation.descr;
          NSRange range = NSMakeRange(self.moreInfoView.descr.text.length - 1, 1);
                     [self.moreInfoView.descr scrollRangeToVisible:range];
                     [UIView beginAnimations: @"moveCNGCallout" context: nil];
          [UIView setAnimationDelegate: self];
          [UIView setAnimationDuration: 0.5];
          [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
          self.moreInfoView.frame = CGRectMake(10.0, 250.0,
self.moreInfoView.frame.size.width, self.moreInfoView.frame.size.height);
          [UIView commitAnimations];

}

- (void)hideAnnotation {
    	
                                                                               4-­‐84	
  
self.moreInfoView.text.text = nil;
            [UIView beginAnimations: @"moveCNGCalloutOff" context: nil];
            [UIView setAnimationDelegate: self];
            [UIView setAnimationDuration: 0.5];
            [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
            self.moreInfoView.frame = CGRectMake(10.0, 250.0 + 300,
    self.moreInfoView.frame.size.width,
    self.moreInfoView.frame.size.height);
            [UIView commitAnimations];
}

- (void)didReceiveMemoryWarning {
      NSLog(@"Attenzione sono con la memoria piena!");

    [super didReceiveMemoryWarning];
       }

- (void)viewDidUnload {

}
- (void)dealloc {

       [poiStore release];
       [mapView release];
       [touchView release];
       [moreInfoView release];
    [super dealloc];
}

#pragma mark -
#pragma mark Button's Method
-(void)cancel{
                    [self dismissModalViewControllerAnimated:YES];
}
@end
	
  
Codice	
  19:	
  Interfaccia	
  e	
  implementazione	
  del	
  TagViewController	
  

Per	
  la	
  visualizzazione	
  di	
  una	
  mappa,	
  il	
  frame	
  work	
  Mapkit	
  offre	
  la	
  possibilità	
  di	
  inserirci	
  al	
  suo	
  interno	
  
dei	
  punti	
  chiamati	
  “pin”	
  per	
  l’identificazione	
  di	
  determinati	
  siti	
  d’interesse	
  per	
  mezzo	
  della	
  creazione	
  
di	
  un’”annotazione”	
  che	
  è	
  composta	
  di	
  due	
  oggetti,	
  uno	
  di	
  tipo	
  “annotation”,	
  chiamato	
  MyAnnotation,	
  	
  e	
  
uno	
  di	
  tipo	
  	
  “visual	
  annotazion”,	
  denominato	
  MoreInfoView.	
  

La	
  classe	
  MyAnnotation	
  implementerà	
  il	
  protocollo	
  MKAnnotation	
  e	
  dovrà	
  contenere	
  le	
  informazioni	
  
riguardanti	
   le	
   coordinate,	
   presenti	
   nella	
   proprietà	
   di	
   tipo	
   CLLocationCoordinate2D,	
   oltre	
   a	
   quelle	
  
opzionali	
  di	
  tipo	
  NSString,	
  relative	
  al	
  nome	
  e	
  alla	
  descrizione	
  del	
  punto.	
  



     	
                                                                                                                                                 4-­‐85	
  
In	
   aggiunta,	
   nella	
   costruzione	
   di	
   questa	
   classe,	
   è	
   stato	
   anche	
   implementato	
   un	
   metodo,	
   chiamato	
  
“initWithCoordinate”,	
   con	
   lo	
   scopo	
   di	
   impostare	
   i	
   valori	
   delle	
   proprietà	
   al	
   momento	
   della	
   sua	
  
inizializzazione.	
  

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

@interface MyAnnotation : NSObject<MKAnnotation> {

            CLLocationCoordinate2D coordinate;
            NSString *name;
            NSString *title;
            NSString *descr;
}

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic,retain) NSString *name;
@property (nonatomic,retain) NSString *title;
@property (nonatomic,retain) NSString *descr;
- (id) initWithCoords:(CLLocationCoordinate2D) coords name:(NSString*) inputName
descr:(NSString*) inputDescr link:(NSString*) inputLink ;
@end
	
  
#import "MyAnnotation.h"
@implementation MyAnnotation

@synthesize coordinate, name, title, descr, link;

- (id) initWithCoords:(CLLocationCoordinate2D) coords name:(NSString*) inputName
descr:(NSString*)inputDescr link:(NSString*)inputLink
{

            self = [super init];
            if (self != nil) {

                  coordinate = coords;
                  self.name = inputName;
                  self.title = inputName;
                  self.descr = inputDescr;
            }
            return self;
}
@end
	
  
	
  



     	
                                                                                                                                       4-­‐86	
  
L’”annotazione	
   visuale”	
   sarà	
   composta	
   dalle	
   classi	
   MoreInfoView	
   e	
   TouchView	
   che	
   serviranno	
   a	
  
descrivere	
  le	
  informazioni	
  dettagliate	
  di	
  ciascun	
  punto	
  e	
  saranno	
  chiamate	
  quando	
  l’utente	
  cliccherà	
  
su	
  un	
  determinato	
  “pin”	
  o	
  su	
  un	
  qualsiasi	
  punto	
  della	
  mappa.	
  	
  

#import <Foundation/Foundation.h>                                                     #import "MoreInfoView.h"

@interface MoreInfoView : UIView {                                                    @implementation MoreInfoView

     IBOutlet UILabel* text;//nome                                                    @synthesize text;
     IBOutlet UITextView                                                              @synthesize descr;
*descr;//descrizione POI                                                              @synthesize linkWiki;
}                                                                                     @end	
  
@property (nonatomic, retain) IBOutlet
UILabel* text;
@property (nonatomic, retain) IBOutlet
UITextView *descr;
@end
#import <UIKit/UIKit.h>                                                               #import "TouchView.h"

@class UIView;                                                                        @interface TouchView ()
                                                                                      - (UIView *)hitTest:(CGPoint)point
@interface TouchView : UIView {                                                       withEvent:(UIEvent *)event;
     id delegate;                                                                     @end
     SEL callAtHitTest;                                                               @implementation TouchView
}                                                                                     @synthesize delegate, callAtHitTest;
@property (assign) id delegate;                                                       - (UIView *)hitTest:(CGPoint)point
@property (assign) SEL callAtHitTest;                                                 withEvent:(UIEvent *)event {

@end                                                                                        UIView* returnMe = [super
	
                                                                                    hitTest:point withEvent:event];
                                                                                            if (![returnMe isKindOfClass:[UIButton
                                                                                      class]]) {
                                                                                                   [delegate
                                                                                      performSelector:callAtHitTest];
                                                                                            }

                                                                                           return returnMe;
                                                                                      }
                                                                                      @end
                                                                                      	
  
Codice	
  20:	
  Interfacce	
  e	
  implementazioni	
  -­	
  In	
  Alto:	
  MoreInfoView	
  -­	
  In	
  Basso:	
  TouchView	
  

4.1.3.2.2 Interfaccia	
  Grafica	
  
L’interfaccia	
   di	
   questa	
   parte	
   del	
   programma	
   è	
   stata	
   impostata	
   sia	
   tramite	
   codice,	
   come	
   si	
   è	
   visto	
   nel	
  
paragrafo	
   precedente,	
   sia	
   tramite	
   l’Interface	
   Builder	
   dove	
   si	
   sono	
   impostati	
   i	
   campi	
   di	
   testo	
   per	
  
l’oggetto	
   UIView	
   collegato	
   alla	
   classe	
   MoreInfoView	
   mentre	
   per	
   quanto	
   riguarda	
   il	
   controller	
  
TagViewController	
   gli	
   elementi	
   grafici	
   sono	
   stati	
   inizializzati	
   tramite	
   l’Xcode	
   all’interno	
   dell’oggetto	
  
grafico	
  UIView,	
  come	
  rappresentato	
  nella	
  figura	
  sottostante.	
  

      	
                                                                                                                                                       4-­‐87	
  
 




                                                                                                              	
  
Figura	
  22:	
  Interfaccia	
  grafica	
  del	
  TagViewController	
  

	
  

4.1.4 Definizione	
  delle	
  funzioni	
  tipiche	
  dei	
  software	
  di	
  navigazione	
  
Questo	
   capitolo	
   tratta	
   lo	
   sviluppo	
   del	
   modulo	
   che	
   include	
   le	
   tipiche	
   funzionalità	
   dei	
   software	
   di	
  
navigazione,	
  come	
  stabilito	
  nelle	
  specifiche	
  precedentemente	
  fissate	
  all’elaborazione	
  del	
  progetto.	
  

Per	
  prima	
  cosa,	
  si	
  è	
  deciso	
  di	
  creare	
  una	
  schermata	
  che	
  includesse	
  la	
  visualizzazione	
  di	
  una	
  mappa	
  e	
  
poi	
   in	
   un	
   secondo	
   momento,	
   la	
   tracciatura	
   del	
   percorso	
   compiuto	
   dall’utente	
   in	
   un	
   determinato	
  
intervallo	
  di	
  tempo,	
  fornendo	
  i	
  dati	
  della	
  sua	
  velocità	
  media	
  e	
  distanza	
  percorsa	
  a	
  processo	
  terminato.	
  

Per	
   la	
   visualizzazione	
   della	
   mappa,	
   si	
   è	
   deciso	
   di	
   integrare	
   l’interfaccia	
   con	
   i	
   tre	
   tipi	
   di	
  
rappresentazione,	
  disponibili	
  già	
  nelle	
  librerie	
  Mapkit:	
  

          ⇒ Standard(o	
  mappa)	
  
          ⇒ Satellite	
  
          ⇒ Hybrid	
  (un’associazione	
  fra	
  la	
  visualizzazione	
  ”Standard”	
  e	
  quella	
  dal	
  satellite)	
  

Nel	
  sistema	
  in	
  questione,	
  grazie	
  al	
  collegamento	
  con	
  il	
  ricevitore	
  GPS,	
  si	
  ha	
  la	
  localizzazione	
  dell’utente	
  
sulla	
   mappa	
   e	
   con	
   l’iterazione	
   del	
   magnetometro,	
   si	
   permette	
   la	
   sua	
   rotazione	
   verso	
   la	
   direzione	
  
dell’utente,	
  facilitando	
  un	
  suo	
  rapido	
  orientamento.	
  




       	
                                                                                                                                           4-­‐88	
  
 
Figura	
  23:	
  Schema	
  di	
  funzionamento	
  del	
  modulo	
  

4.1.4.1 Funzionamento	
  
Questo	
  modulo	
  del	
  programma	
  è	
  costituito	
  da	
  due	
  view	
  controller:	
  

        1. TrackingViewController	
  
        2. TrackingView	
  

Quando	
   l’utente	
   vuole	
   registrare	
   il	
   percorso,	
   invocherà	
   e	
   inizializzerà	
   dall’interfaccia	
   grafica	
   il	
  
TrackingViewController.	
  

Esso,	
  al	
  suo	
  caricamento,	
  si	
  collegherà	
  a	
  GoogleMaps	
  tramite	
  il	
  frame	
  work	
  Mapkit	
  e,	
  interagendo	
  con	
  il	
  
ricevitore	
  GPS,	
  visualizzerà	
  con	
  un	
  pin,	
  la	
  sua	
  posizione	
  sulla	
  mappa.	
  

4.1.4.1.1 TrackingViewController	
  

4.1.4.1.1.1 Funzionamento	
  
Questo	
   controller	
   avrà	
   il	
   compito	
   di	
   creare	
   l’iterazione	
   tra	
   il	
   controller	
   delegato	
   alla	
   visualizzazione	
  
della	
  mappa,	
  ossia	
  il	
  TrackingView	
  e	
  le	
  periferiche	
  del	
  dispositivo,	
  quali	
  il	
  ricevitore	
  GPS	
  e	
  la	
  bussola	
  
attraverso	
  i	
  seguenti	
  passaggi:	
  

        •   Il	
   CLLocationManager	
   monitorerà	
   gli	
   aggiornamenti	
   della	
   posizione	
   dell’utente	
   e	
   dei	
   valori	
  
            della	
   bussola,	
   mandando	
   poi	
   dei	
   messaggi	
   al	
   view	
   controller	
   per	
   aggiornare	
   graficamente	
  
            l’inclinazione	
   della	
   mappa	
   con	
   l’utilizzo	
   della	
   classe	
   CLHeading	
   e	
   il	
   disegno	
   del	
   percorso	
  
            compiuto	
   dall’utente	
   sulla	
   mappa	
   tramite	
   l’uso	
   della	
   classe	
   CLLocation,	
   per	
   ricavare	
   le	
  
            coordinate	
  della	
  latitudine	
  e	
  longitudine	
  e	
  per	
  trovare	
  la	
  distanza	
  percorsa	
  dall’utente	
  ;	
  
        •   Per	
   calcolare	
   il	
   tempo	
   impiegato	
   per	
   il	
   tragitto,	
   il	
   programma	
   necessiterà	
   anche	
   del	
   periodo	
   in	
  
            cui	
  si	
  è	
  iniziata	
  e	
  conclusa	
  la	
  misurazione,	
  con	
  l’utilizzo	
  della	
  classe	
  NSDate.	
  

I	
  tre	
  metodi	
  sviluppati	
  per	
  lo	
  svolgimento	
  di	
  queste	
  operazioni	
  saranno	
  chiamati	
  rispettivamente:	
  

     1. selectMap:	
  
     2. toggleTracking:	
  
     3. resetMap:	
  

Il	
   primo	
   sarà	
   quello	
   chiamato	
   per	
   la	
   modifica	
   della	
   visualizzazione	
   della	
   mappa	
   che	
   sarà	
   modificata	
  
andando	
  ad	
  agire	
  sull’istanza	
  della	
  classe	
  MKMapView.	
  


     	
                                                                                                                                                      4-­‐89	
  
Il	
   metodo	
   toggleTracking	
   sarà	
   richiamato	
   quando	
   l’utente	
   vorrà	
   stabilire	
   il	
   percorso	
   compiuto	
   in	
   un	
  
determinato	
   tempo,	
   rilevando	
   a	
   fine	
   evento	
   la	
   velocità	
   media	
   tenuta	
   dalla	
   persona	
   e	
   la	
   distanza	
  
percorsa.	
  

Quest’ultimo	
   dato	
   sarà	
   fornito	
   direttamente	
   dalla	
   sommatoria	
   tra	
   i	
   risultati	
   della	
   funzione	
   della	
  
libreria	
  chiamata	
  getDistanceFrom	
  che	
  opererà	
  sulla	
  differenza	
  fra	
  le	
  coordinate	
  del	
  punto	
  di	
  arrivo	
  e	
  
quello	
  di	
  partenza,	
  mentre	
  il	
  tempo	
  sarà	
  ottenuto	
  dalla	
  differenza	
  fra	
  la	
  memorizzazione	
  del	
  periodo	
  di	
  
fine	
  misurazione	
  e	
  quello	
  d’inizio.	
  

Il	
  terzo	
  metodo	
  invece	
  servirà	
  a	
  cancellare	
  tutti	
  i	
  punti	
  finora	
  considerati	
  per	
  il	
  disegno	
  del	
  percorso	
  
sulla	
  mappa.	
  

La	
  manipolazione	
  della	
  mappa	
  sarà	
  delegata	
  alla	
  classe	
  derivata	
  UIView	
  che	
  consentirà	
  di	
  disegnare	
  su	
  
di	
  essa	
  il	
  percorso	
  e	
  che	
  implementerà	
  i	
  metodi	
  per	
  la	
  gestione	
  della	
  classe	
  MKMapView.	
  	
  

#import        <UIKit/UIKit.h>
#import        <MapKit/MapKit.h>
#import        <CoreLocation/CoreLocation.h>
#import        "TrackingView.h"

@interface TrackingViewController :
UIViewController<MKMapViewDelegate,CLLocationManagerDelegate> {

            IBOutlet MKMapView *mapView;
            TrackingView *trackingView;
            UIBarButtonItem *startButton;
            UIBarButtonItem *resetButton;
            UISegmentedControl *segmentTypeMap;

            //indice di selezione
            int selectedSegment;

            CLLocationManager *locationManager;
            CLHeading *heading;
            NSDate *startDate;
            float distance;
            BOOL tracking;//per vedere se è già in atto la traccia del percorso

}
@property (nonatomic, retain) MKMapView * mapView;
@property (nonatomic, retain) TrackingView *trackingView;
@property (nonatomic, retain) UIBarButtonItem *startButton;
@property (nonatomic, retain) UIBarButtonItem *resetButton;

@property (nonatomic, retain) UISegmentedControl *segmentTypeMap;

@end	
  
#import "TrackingViewController.h"
@implementation TrackingViewController

     	
                                                                                                                                            4-­‐90	
  
//Pulsanti
@synthesize startButton, resetButton, segmentTypeMap;//bottoni per la partenza ed il
reset del sistema
//mappa
@synthesize mapView, trackingView;

#pragma mark -
#pragma mark Lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
   [super viewDidLoad];
      tracking = NO;

           //NSLog(@"Sono in viewDidLoad");
           }

- (void)didReceiveMemoryWarning
      {
      // Releases the view if it doesn't have a superview.
   [super didReceiveMemoryWarning];

           // Release any cached data, images, etc that aren't in use.
}



- (void)viewWillAppear:(BOOL)animated {
      NSLog(@"sono in viewWillAppear..");
      tracking = NO;

           //pulsanti sul lato sx della toolbar
           // creo una toolbar che conterrà 2 pulsanti
           UIToolbar* tools = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 80, 44.01)];

      // creo l'array che contiene i pulsanti, che saranno aggiunti alla toolba
      NSMutableArray* buttons = [[NSMutableArray alloc] initWithCapacity:2];
      // creo il pulsante di start
       startButton = [[UIBarButtonItem alloc] initWithTitle:@"Start"
style:UIBarButtonItemStyleBordered target:self action:@selector(toggleTracking)];
      [buttons addObject:startButton];
      [startButton release];
      // creo il reset
      resetButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self
action:@selector(resetMap)];
      //initWithTitle:@"Reset" style:UIBarButtonItemStyleBordered target:self
    	
                                                                                         4-­‐91	
  
action:@selector(resetMap)];
     [buttons addObject:resetButton];
     [resetButton release];

          //fisso i bottoni nella toolbar
          [tools setItems:buttons animated:NO];

          [buttons release];

     // inserisco la toolbar nella nav bar
     self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithCustomView:tools];
     [tools release];
     //pulsanti sulla destra del navigation bar
     //creo un array di stringhe per i pulsanti..
     NSMutableArray *controls = [[NSMutableArray alloc] init];
     [controls addObject:@"Map"];
     [controls addObject:@"Satellite"];
     [controls addObject:@"Hybrid"];
     segmentTypeMap = [[UISegmentedControl alloc] initWithItems:controls];
     [segmentTypeMap setSegmentedControlStyle:UISegmentedControlStyleBar];
     [segmentTypeMap setMomentary:TRUE];
     [segmentTypeMap addTarget:self action:@selector(selectMap:)
forControlEvents:UIControlEventValueChanged];
     selectedSegment = [segmentTypeMap selectedSegmentIndex];
     UIBarButtonItem *segmentTypeBtn = [[UIBarButtonItem alloc]
initWithCustomView:segmentTypeMap];
     [segmentTypeMap release];
     [self.navigationItem setRightBarButtonItem:segmentTypeBtn];
     [segmentTypeBtn release];
     // inizializzo TrackingView
     trackingView = [[TrackingView alloc] initWithFrame:mapView.frame];

          // aggiungo trackingView come subview a mapView
          [mapView addSubview:trackingView];
          [trackingView release]; // release di TrackingView

          // imposto come delegate di mapView, trackingView
          mapView.delegate = trackingView;

          // inizializzazione del location manager
          locationManager = [[CLLocationManager alloc] init];

          // impostazione del delegate del locationManager
          locationManager.delegate = self;


   	
                                                                        4-­‐92	
  
//set dell'accuratezza della rappresentazione
          locationManager.desiredAccuracy = kCLLocationAccuracyBest;

          BOOL headingAvailable = [locationManager headingAvailable];

     if (headingAvailable==NO) {
     UIAlertView * erroreAlert = [[UIAlertView alloc]initWithTitle:@"Errore nella bussola
" message:@"Bussola non supportata!L'applicazione terminerà." delegate:nil
cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
     [erroreAlert show];
     [erroreAlert release];
     exit(1);

          }

          [super viewWillAppear:animated];



}
- (void)viewDidUnload {
      // Release any retained subviews of the main view.
      // e.g. self.myOutlet = nil;
}



- (void)dealloc {
      [startButton release];
      [resetButton release];
      [mapView release]; // release the mapView MKMapView
      [segmentTypeMap release];
      [locationManager release];
   [super dealloc];
}



#pragma mark -
#pragma mark Button's method

- (void)toggleTracking
{
      if (tracking)
      {
      tracking = NO; // stop tracking

          // l'iPhone può essere in standby
          [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
   	
                                                                                 4-­‐93	
  
[startButton setTitle:@"Start!"]; // aggiornamento del startButton
           [locationManager stopUpdatingLocation]; // stop tracking location
           [locationManager stopUpdatingHeading]; // stop tracking heading
           mapView.scrollEnabled = YES; // permette all'utente di fare il scroll della map
           mapView.zoomEnabled = YES; // zoom della mappa

           // tempo trascorso con l'inizio del percorso
           float time = -[startDate timeIntervalSinceNow];

           // format the ending message with various calculations
           NSString *message = [NSString stringWithFormat:
                                      @"Distanza percorsa: %.02f km, Velocità: %.02f km/h",
                                      distance / 1000, distance * 3.6 / time];

     // create an alert that shows the message
     UIAlertView *alert = [[UIAlertView alloc]
                                   initWithTitle:@"Dati percorso.." message:message
delegate:self
                                   cancelButtonTitle:@"OK" otherButtonTitles:nil];
     [alert show]; // show the alert
     [alert release]; // release the alert UIAlertView
     } // end if
     else // inizio misurazione
     {
     tracking = YES; // start t
     mapView.scrollEnabled = NO;
     mapView.zoomEnabled = NO;

           // impostazione standby dell'iphone
           [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
           [startButton setTitle: @"Stop"]; // impostazione del titolo del pulsante
           distance = 0.0; // reset
           startDate = [[NSDate date] retain]; // memoriazzazione tempo di partenza
           [locationManager startUpdatingLocation]; // start tracking
           [locationManager startUpdatingHeading]; // start heading
           } //

}

- (void)resetMap
{
      NSLog(@"Sono in reset!");
       [trackingView reset];

}
-(void)selectMap:(id)sender
    	
                                                                                       4-­‐94	
  
{
           UISegmentedControl *segmentControl = sender;
           selectedSegment = [segmentControl selectedSegmentIndex];

           // impostazione del tipo di map
           switch (selectedSegment)
           {
                // standard map
           case 0: mapView.mapType = MKMapTypeStandard; break;

                // satellite map
           case 1: mapView.mapType = MKMapTypeSatellite; break;

                // hybrid map
           case 2: mapView.mapType = MKMapTypeHybrid; break;
           } //

}

#pragma mark -
#pragma mark MKMapViewDelegate
// delegate method for the MKMapView
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:
(id <MKAnnotation>)annotation
{
      return nil; //nessuna annotazione
} //
#pragma mark -
#pragma mark CLLocationManager
// the location manager updates the current location
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:
(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
      // nuova posizione sulla mappa
      [trackingView addPoint:newLocation];

           // in caso che c sia una vecchia posizione
           if (oldLocation != nil)
           {

           distance += [newLocation getDistanceFrom:oldLocation];
           }

           // creo una regione centrata attorno al nuovo punto
           MKCoordinateSpan span = MKCoordinateSpanMake(0.005, 0.005);


    	
                                                                      4-­‐95	
  
// creo una MKCoordinateRegion centrata attorno alla nuova posizione
            MKCoordinateRegion region =
            MKCoordinateRegionMake(newLocation.coordinate, span);

            [mapView setRegion:region animated:YES];
}
// location manager updates the heading
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:
(CLHeading *)newHeading
{
      // rotazione in radianti
      float rotation = newHeading.trueHeading * M_PI / 180;
      // reset transform
      mapView.transform = CGAffineTransformIdentity;
      // creazione di una nuova transform con l'angolo
      CGAffineTransform transform = CGAffineTransformMakeRotation(-rotation);
      mapView.transform = transform; // apply the new transform
}

// CLLocationManager fails
- (void)locationManager:(CLLocationManager *)manager didFailWithError:
(NSError *)error
{

            if ([error code] == kCLErrorDenied)
            [locationManager stopUpdatingLocation];

            NSLog(@"location manager fallito");
}
@end
	
  
	
  Codice	
  21:	
  Interfaccia	
  e	
  implementazione	
  del	
  TrackingViewController	
  

4.1.4.1.1.1.1 Interfaccia	
  Grafica	
  
La	
   grafica	
   è	
   organizzata	
   attraverso	
   l’Interface	
   Builder	
   con	
   l’inserimento	
   nel	
   view	
   controller	
  
dell’oggetto	
   MKMapView	
   che	
   è	
   dimensionato	
   sull’intera	
   maschera	
   e	
   la	
   cui	
   organizzazione	
   è	
   delegata	
  
invece	
  al	
  codice	
  che	
  gestisce	
  l’invocazione	
  di	
  determinati	
  eventi.	
  




     	
                                                                                                                                     4-­‐96	
  
 
Figura	
  24:	
  Interfaccia	
  grafica	
  del	
  TrackingViewController	
  

	
  

4.1.4.1.2 TrackingView.	
  
Questo	
   controller	
   è	
   stato	
   aggiunto	
   nella	
   sub-­‐view	
   dell’elemento	
   MKMapView:	
   esso	
   presenterà	
   dei	
  
metodi	
   d’inizializzazione	
   della	
   grafica	
   che	
   consentiranno	
   la	
   loro	
   gestione	
   da	
   codice:	
   ad	
   esempio	
   il	
  
metodo	
   “drawRect”	
   sarà	
   utilizzato	
   nel	
   disegno	
   del	
   percorso	
   sulla	
   mappa,	
   mentre	
   i	
   metodi	
  
“initWithFrame”	
  e	
  “addPoint”	
  serviranno	
  rispettivamente,	
  il	
  primo	
  ad	
  inizializzare	
  il	
  frame	
  grafico	
  del	
  
TrackingViewController,	
   mentre	
   il	
   	
   secondo	
   ad	
   aggiungere	
   i	
   punti	
   del	
   percorso	
   in	
   un	
   array	
   in	
   cui	
  
saranno	
  contenute	
  le	
  coordinate	
  di	
  ogni	
  singolo	
  punto.	
  

Oltre	
   a	
   questi	
   metodi,	
   implementerà	
   quelli	
   relegati	
   alla	
   gestione	
   della	
   mappa,	
   come	
   il	
   metodo	
  
“regionDidChangedAnimated”	
   che	
   aggiornerà	
   la	
   “regione”	
   di	
   visualizzazione	
   della	
   mappa	
   e	
   il	
  
“regionWillChangeAnimated”	
  invocato	
  quando	
  la	
  regione	
  di	
  visualizzazione	
  sarà	
  cambiata	
  dall’utente.	
  	
  	
  

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>

@interface TrackingView : UIView<MKMapViewDelegate> {
         NSMutableArray *points;
}
//aggiungo un nuovo punto all'array points
- (void)addPoint:(CLLocation *)point;
- (void)reset;
@end	
  
#import "TrackingView.h"
#import <MapKit/MKMapView.h>


       	
                                                                                                                                              4-­‐97	
  
static const int ARROW_THRESHOLD = 50;

@implementation TrackingView
- (id)initWithFrame:(CGRect)frame {
   if (self = [super initWithFrame:frame]) {
      self.backgroundColor = [UIColor clearColor]; // set the background
             points = [[NSMutableArray alloc] init];
   }
   return self;
}



- (void)drawRect:(CGRect)rect {
   if (points.count == 1 || self.hidden)
            return;

          // ottengo il contesto grafico corrente
          CGContextRef context = UIGraphicsGetCurrentContext();
          CGContextSetLineWidth(context, 4.0); // set the line width
          CGPoint point; //
          float distance = 0.0; // initialize distance to 0.0

          // ciclo for per tutti i punti
          for (int i = 0; i < points.count; i++)
          {
                float f = (float)i; // cast i as a float and store in f



                CGContextSetRGBStrokeColor(context, 0, 1 - f / (points.count - 1),
                                              f / (points.count - 1), 0.8);

          CLLocation *nextLocation = [points objectAtIndex:i];
          CGPoint lastPoint = point; // store point in lastPoint
          point = [(MKMapView *)self.superview convertCoordinate:
nextLocation.coordinate toPointToView:self];

                // se questo non è l’ultimo punto
                if (i != 0)
                {
                        // mi muovo dall’ultimo punto
                        CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);

                      // aggiungo una linea
                      CGContextAddLineToPoint(context, point.x, point.y);

                      // add the length of the line drawn to distance
   	
                                                                                4-­‐98	
  
distance += sqrt(pow(point.x - lastPoint.x, 2) +
                                          pow(point.y - lastPoint.y, 2));



                    if (distance >= ARROW_THRESHOLD)
                    {
                           // carico l’immagine della freccia
                           UIImage *image = [UIImage imageNamed:@"arrow.png"];
                           CGRect frame; // declare frame CGRect

                          // calculate the point in the middle of the line
                          CGPoint middle = CGPointMake((point.x + lastPoint.x) / 2,
                                                                   (point.y + lastPoint.y) / 2);



                          frame.size.width = image.size.width;
                          frame.size.height = image.size.height;

                          frame.origin.x = middle.x - frame.size.width / 2;

                          frame.origin.y = middle.y - frame.size.height / 2;

                        //salvo gli stati grafici
          CGContextSaveGState(context);

                        // centro il contesto nel quale disegnare la freccia
          CGContextTranslateCTM(context, frame.origin.x +
                                                      frame.size.width / 2, frame.origin.y + 
                                                      frame.size.height / 2);

                          //calcolo l’angolo con il quale ruoterò l’immagine della freccia
                          float angle = atan((point.y - lastPoint.y) / (point.x -

lastPoint.x));

                          // se questo punto è a sx dell’ultimo punto
                          if (point.x < lastPoint.x)
                                angle += 3.14159; // incremento l’angolo di pi

                          // ruoto il contesto dell’angolo stabilito
                          CGContextRotateCTM(context, angle);

                          // disegno l’immagine nel contesto ruotato
                          CGContextDrawImage(context, CGRectMake(-frame.size.width / 2,
                                                                      -frame.size.height
/ 2, frame.size.width,
   	
                                                                                              4-­‐99	
  
frame.size.height),
image.CGImage);
                            CGContextRestoreGState(context);
                            distance = 0.0; // reset distance
                      } // end if
                } // end if

                 CGContextStrokePath(context); //disegno il percorso
           } // end for

}

// aggiungo un nuovo punto all’array
- (void)addPoint:(CLLocation *)point
{
      // store last element of point
      CLLocation *lastPoint = [points lastObject];

           //se il nuovo punto è in una diversa locazione rispetto all’ultimo punto
           if (point.coordinate.latitude != lastPoint.coordinate.latitude ||
                 point.coordinate.longitude != lastPoint.coordinate.longitude)
           {
                 [points addObject:point]; // aggiungo il punt
                 [self setNeedsDisplay]; // ridisegno la view
           } // end if
}

// rimuovo tutti i punti e aggiorno la view
- (void)reset
{
      [points removeAllObjects];
      [self setNeedsDisplay];
} // end method reset

// called by the MKMapView when the region is going to change
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:
(BOOL)animated
{
      self.hidden = YES; // hide the view during the transition
} // end method mapView:regionWillChangeAnimated:

// called by the MKMapView when the region has finished changing
- (void)mapView:(MKMapView *)mapView
regionDidChangeAnimated:(BOOL)animated
{
      self.hidden = NO; // unhide the view
    	
                                                                                          4-­‐100	
  
[self setNeedsDisplay]; // redraw the view
} // end method mapview:regionDidChangeAnimated:
- (void)dealloc {
     [super dealloc];
}
@end
	
  
Codice	
  22:	
  Interfaccia	
  e	
  implementazione	
  del	
  TrackingView	
  

4.2 Lo	
  sviluppo	
  del	
  programma	
  completo	
  
Per	
  unire	
  i	
  due	
  gruppi	
  di	
  moduli	
  sviluppati	
  per	
  l’applicazione	
  definitiva,	
  ovvero	
  quello	
  che	
  implementa	
  
ed	
  elabora	
  l’Augmented	
  Reality	
  e	
  quello	
  che	
  invece	
  comprende	
  le	
  funzioni	
  basilari	
  di	
  un	
  navigatore,	
  	
  si	
  
è	
  deciso	
  di	
  utilizzare	
  l’elemento	
  Tab	
  Bar.	
  

Questo	
  elemento	
  è	
  composto	
  di	
  due	
  o	
  più	
  schede	
  situate	
  nella	
  parte	
  inferiore	
  della	
  maschera,	
  ognuna	
  
delle	
  quali,	
  contiene	
  un	
  view	
  controller.	
  Un	
  utente,	
  quindi,	
  selezionando	
  una	
  delle	
  schede	
  poste	
  nel	
  tab	
  
bar	
  caricherà	
  un	
  view	
  controller	
  con	
  la	
  vista	
  associata.	
  	
  

Il	
  suo	
  utilizzo	
  sarà	
  molto	
  utile	
  perché	
  consentirà	
  di	
  presentare	
  nelle	
  applicazioni	
  più	
  sotto	
  processi	
  o	
  
viste	
  degli	
  stessi	
  dati:	
  ogni	
  scheda	
  corrisponderà	
  a	
  un	
  sub-­‐task	
  dell’applicazione	
  principale.	
  

Ogni	
   applicazione	
   per	
   Iphone	
   che	
   userà	
   un	
   tab	
   bar	
   dovrà	
   implementare	
   nella	
   classe	
   che	
   utilizzerà	
   i	
  
protocolli	
  UIApplicationDelegate	
  e	
   UITabBarControllerDelegate,	
   oltre	
  a	
  dover	
  dichiarare	
  la	
  proprietà	
  
dell’oggetto	
  UITabBarController:	
  questo	
  permetterà	
  l’esistenza	
  dell’oggetto	
  per	
  tutto	
  il	
  ciclo	
  di	
  vita	
  del	
  
programma.	
  

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface CompactNavigatorAppDelegate : NSObject <UIApplicationDelegate,
UITabBarControllerDelegate> {
   NSManagedObjectModel *managedObjectModel;
   NSManagedObjectContext *managedObjectContext;
   NSPersistentStoreCoordinator *persistentStoreCoordinator;
   IBOutlet UIWindow *window;
     IBOutlet UITabBarController *tabBarController;
}
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSManagedObjectContext
*managedObjectContext;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator
*persistentStoreCoordinator;
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
- (NSString *)applicationDocumentsDirectory;
@end	
  
#import "CompactNavigatorAppDelegate.h"
#import "RootViewController.h"

@implementation CompactNavigatorAppDelegate


      	
                                                                                                                                              4-­‐101	
  
@synthesize window;
@synthesize tabBarController;



#pragma mark -
#pragma mark Application lifecycle

- (void)applicationDidFinishLaunching:(UIApplication *)application {
   // Override point for customization after app launch
      [window addSubview:tabBarController.view];
      [window makeKeyAndVisible];
}
/**
 applicationWillTerminate: saves changes in the application's managed object context before
the application terminates.
 */
- (void)applicationWillTerminate:(UIApplication *)application {

    NSError *error = nil;
    if (managedObjectContext != nil) {
       if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
                  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                  abort();
       }
    }
}



#pragma mark -
#pragma mark Core Data stack

/**
 Returns the managed object context for the application.
 If the context doesn't already exist, it is created and bound to the persistent store
coordinator for the application.
 */
- (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext != nil) {
       return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
       managedObjectContext = [[NSManagedObjectContext alloc] init];
       [managedObjectContext setPersistentStoreCoordinator: coordinator];
    	
                                                                                   4-­‐102	
  
}
    return managedObjectContext;
}

/**
 Returns the managed object model for the application.
 If the model doesn't already exist, it is created by merging all of the models found in the
application bundle.
 */
- (NSManagedObjectModel *)managedObjectModel {
    if (managedObjectModel != nil) {
       return managedObjectModel;
    }
    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
    return managedObjectModel;
}
/**
 Returns the persistent store coordinator for the application.
 If the coordinator doesn't already exist, it is created and the application's store added to
it.
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

   if (persistentStoreCoordinator != nil) {
      return persistentStoreCoordinator;
   }
   NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: @"photo.sqlite"]];//CompactNavigator.sqlite
       NSError *error = nil;
   persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
   if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeUrl options:nil error:&error]) {
             NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
             abort();
   }
   return persistentStoreCoordinator;
}

#pragma mark -
#pragma mark Application's Documents directory

/**
 Returns the path to the application's Documents directory.
 */
- (NSString *)applicationDocumentsDirectory {
    	
                                                                                  4-­‐103	
  
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) lastObject];
}

#pragma mark -
#pragma mark Memory managemen
- (void)dealloc {
   [managedObjectContext release];
   [managedObjectModel release];
   [persistentStoreCoordinator release];

            [window release];
            [super dealloc];
}
@end
	
  
Codice	
  23:	
  Interfaccia	
  e	
  implementazione	
  del	
  CompactNavigatorAppDelegate	
  

Per	
   quanto	
   riguarda	
   l’impostazione	
   dell’interfaccia	
   grafica,	
   si	
   dovrà	
   aprire	
   il	
   file	
   MainView.xib	
   con	
  
l’Interface	
   Builder	
   e	
   aggiungere	
   l’oggetto	
   UITabBarController,	
   collegandolo	
   tramite	
   l’Inspector	
   alla	
  
proprietà	
  del	
  medesimo	
  tipo	
  dichiarata	
  nel	
  file	
  CompactNavigatorAppDelegate.	
  




                                                                                                                                  	
  	
  
Figura	
  25:	
  Impostazione	
  dell'interfaccia	
  grafica	
  

A	
   questo	
   punto,	
   s’imposteranno	
   i	
   view	
   controller	
   per	
   ogni	
   scheda	
   collocata	
   nel	
   tab	
   bar	
   attraverso	
  
l’Inspector,	
   alla	
   voce	
   “Attributes”,	
   dove	
   sarà	
   settato	
   il	
   “nib	
   file”	
   e	
   la	
   sua	
   classe	
   corrispondente	
  
all’interfaccia	
  grafica	
  voluta.	
  

Per	
   completare	
   infine	
   i	
   collegamenti	
   tra	
   le	
   varie	
   form,	
   soprattutto	
   nel	
   sistema	
   dell’Augmented	
   Reality,	
  
si	
   è	
   deciso	
   di	
   comprendere	
   nell’insieme	
   dei	
   controller	
   la	
   barra	
   di	
   navigazione	
   detta	
   altresì	
   anche	
  
“navigation	
  bar”,	
  con	
  lo	
  scopo	
  di	
  tenere	
  sempre	
  uno	
  stesso	
  contesto	
  tra	
  un	
  controller	
  l’altro.	
  

     	
                                                                                                                                             4-­‐104	
  
Questa	
   parte	
   è	
   ottenuta	
   sia	
   attraverso	
   l’editing	
   da	
   codice,	
   creando	
   le	
   classi	
   dei	
   controller	
   con	
  
l’implementazione	
   del	
   protocollo	
   “UINavigationControllerDelegate”	
   e	
   l’inizializzazione	
   del	
   navigation	
  
bar	
   con	
   la	
   creazione	
   dei	
   pulsanti	
   per	
   consentire	
   all’utente	
   d’invocare	
   determinati	
   eventi,	
   sia	
   tramite	
  
l’Interface	
   Builder	
   con	
   la	
   predispozione	
   delle	
   singole	
   form	
   a	
   visualizzare	
   la	
   navigation	
   bar,	
   come	
  
mostrato	
  nella	
  figura	
  sottostante.	
  




                                                                                                          	
  
Figura	
  26:	
  Impostazione	
  della	
  visualizzazione	
  della	
  navigation	
  bar	
  sul	
  MainWindow.xib	
  

Attraverso	
  l’Xcode,	
  per	
  l’editing	
  del	
  codice,	
  le	
  azioni	
  correlate	
  all’implementazione	
  del	
  Navigation	
  bar	
  
potranno	
  ad	
  esempio,	
  essere	
  le	
  seguenti:	
  

              ⇒   Il	
  ritorno	
  a	
  una	
  form	
  precedente	
  a	
  quella	
  aperta	
  
              ⇒   L’apertura	
  di	
  una	
  successiva	
  maschera	
  
              ⇒   Il	
  salvataggio	
  di	
  dati	
  
              ⇒   L’annullamento	
  di	
  una	
  determinata	
  azione	
  

Va	
   ricordato	
   che	
   le	
   azioni	
   dovranno	
   essere	
   associate	
   a	
   pulsanti	
   di	
   tipo	
   “UIBarButtonItem”	
   che	
   poi	
  
saranno	
   posti	
   sul	
   lato	
   destro	
   o	
   sinistro	
   della	
   navigation	
   bar	
   attraverso	
   l’impostazione	
   delle	
   seguenti	
  
proprietà:	
  

          ⇒ self.navigationItem.leftBarButtonItem	
  =	
  cancelButton	
  
          ⇒ self.navigationItem.rightBarButtonItem	
  =	
  saveButton;	
  


5 COLLAUDO	
  
	
  
La	
  fase	
  di	
  collaudo	
  del	
  programma	
  appena	
  descritto,	
  deve	
  essere	
  attuata	
  in	
  primo	
  luogo	
  sul	
  simulatore	
  
disponibile	
  nel	
  tool	
  di	
  sviluppo	
  dell’SDK.	
  

Il	
  problema	
  principale	
  è	
  che	
  non	
  tutto	
  può	
  essere	
   simulato	
  dal	
  computer;	
  in	
  particolare	
  la	
  periferica	
  
interna	
   di	
   cui	
   non	
   si	
   ha	
   una	
   simulazione	
   è	
   la	
   fotocamera,	
   quindi	
   per	
   riuscire	
   a	
   far	
   funzionare	
   il	
  
programma	
   è	
   stato	
   necessario	
   inserire	
   nel	
   codice,	
   delle	
   verifiche	
   sull’uso	
   della	
   periferica	
   stessa	
   in	
  
modo	
  da	
  non	
  mandare	
  in	
  crash	
  il	
  simulatore.	
  



       	
                                                                                                                                                    5-­‐105	
  
5.1 Collaudo	
  sull’Iphone	
  simulator	
  
Per	
  essere	
  testato,	
  il	
  programma	
  deve	
  essere	
  aperto	
  tramite	
  l’Xcode,	
  il	
  quale	
  è	
  dotato	
  di	
  un	
  pulsante	
  
chiamato	
   “Build	
   and	
   Run”	
   che	
   è	
   delegato	
   al	
   caricamento	
   del	
   programma	
   sul	
   simulatore	
   e	
   che	
   ha	
  
permesso	
  di	
  testare	
  volta	
  per	
  volta	
  il	
  programma	
  sviluppato.	
  	
  

Anche	
  in	
  questa	
  fase,	
  per	
  agevolare	
  il	
  test,	
  si	
  è	
  preferito	
  comunque	
  suddividere	
  il	
  collaudo	
  su	
  più	
  fasi:	
  

          ⇒ Visualizzazione	
  dei	
  punti	
  d’interesse	
  già	
  memorizzati;	
  
          ⇒ Inserimento	
  manuale	
  dei	
  punti	
  d’interesse	
  dell’utente;	
  
          ⇒ Distribuzione	
  dei	
  POI	
  memorizzati	
  internamente	
  e	
  disponibili	
  su	
  web	
  service,	
  sulla	
  mappa	
  di	
  
            Google	
  Maps;	
  
          ⇒ Simulazione	
  dell’”Augmented	
  Reality”;	
  
          ⇒ Test	
  delle	
  funzionalità	
  di	
  navigazione.	
  

Come	
  già	
  precisato	
  in	
  precedenza,	
  il	
  programma	
  intero	
  è	
  stato	
  suddiviso	
  in	
  due	
  parti,	
  le	
  cui	
  schermate,	
  
sono	
   rappresentate	
   qui	
   di	
   seguito.	
   Per	
   unire	
   queste	
   due	
   parti,	
   si	
   è	
  utilizzato	
   un	
   Tab	
   Bar,	
   ovvero	
   una	
  
barra	
  il	
  cui	
  scopo	
  è	
  quello	
  di	
  unire	
  “viste	
  ”	
  multiple,	
  che	
  in	
  questo	
  caso	
  sono	
  quelle	
  riguardanti	
  i	
  moduli	
  
dell’”Augmented	
  Reality”	
  e	
  i	
  moduli	
  inerenti	
  le	
  funzioni	
  di	
  navigazione.	
  

Per	
   quanto	
   concerne	
   invece	
   l’accorpamento	
   delle	
   viste	
   di	
   un	
   singolo	
   modulo,	
   si	
   è	
   preferito	
   l’uso	
   del	
  
“Navigation	
  Bar”	
  che	
  ha	
  come	
  scopo	
  quello	
  creare	
  un	
  contesto	
  comune	
  in	
  un	
  “set”	
  di	
  form	
  e	
  che	
  può	
  
contenere	
  pulsanti	
  atti	
  ad	
  invocare	
  eventi	
  riguardanti	
  quella	
  determinata	
  vista.	
  	
  

	
  




                                                                                                                                                                               	
  
                                                                                        	
  
Figura	
  27:	
  Descrizione	
  interfacce	
  grafiche	
  

	
  

5.2 Visualizzazione	
  dei	
  punti	
  d’interesse	
  	
  
Questa	
   parte	
   dell’interfaccia,	
   si	
   trova	
   nel	
   modulo	
   in	
   cui	
   è	
   implementata	
   l’Augmented	
   Reality	
   e	
   ha	
  
l’obiettivo	
  di	
  visualizzare	
  i	
  dati	
  dei	
  punti	
  sotto	
  forma	
  di	
  una	
  tabella	
  in	
  cui	
  si	
  renderanno	
  in	
  evidenza	
  i	
  
nomi	
  degli	
  stessi	
  inseriti	
  dall’utente.	
  

Il	
   controller	
   che	
   è	
   delegato	
   a	
   questa	
   visualizzazione	
   è	
   quello	
   che	
   si	
   trova	
   nella	
   figura	
   27	
   sul	
   lato	
  
sinistro:	
  esso	
  avrà	
  il	
  compito	
  di	
  memorizzare,	
  visualizzare	
  i	
  dati	
  disponibili	
  e	
  gestire	
  le	
  librerie	
  dell’AR,	
  
consentendo	
   all’utente	
   di	
   coordinare	
   tutte	
   le	
   form	
   incaricate	
   a	
   svolgere	
   questi	
   compiti,	
   tramite	
   i	
  
pulsanti	
  situati	
  sul	
  Navigation	
  Bar.	
  

       	
                                                                                                                                                       5-­‐106	
  
5.3 Inserimento	
  manuale	
  dei	
  punti	
  d’interesse	
  dell’utente	
  
Quando	
  l’utente	
  si	
  troverà	
  sulla	
  form,	
  avrà	
  la	
  possibilità	
  di	
  compilare	
  i	
  campi	
  riguardanti	
  il	
  nome	
  e	
  la	
  
descrizione	
   del	
   punto	
   mentre	
   quelli	
   riguardanti	
   la	
   latitudine	
   e	
   la	
   longitudine	
   saranno	
   non	
   modificabili	
  
e	
  compilati	
  dal	
  programma	
  con	
  l’ausilio	
  del	
  sensore	
  GPS.	
  	
  Eventualmente,	
  il	
  cliente,	
  avrà	
  la	
  possibilità	
  
di	
  scegliere	
  le	
  foto	
  salvate	
  in	
  precedenza	
  del	
  punto	
  stesso,	
  oppure	
  di	
  scattarle	
  direttamente,	
  gestendo	
  
da	
  programma	
  la	
  fotocamera	
  con	
  il	
  corretto	
  pulsante.	
  

	
  




                                                                                                	
  
Figura	
  28:	
  Memorizzazione	
  delle	
  informazioni	
  di	
  un	
  punto	
  

Se	
  l’utente	
  deciderà	
  di	
  scegliere	
  una	
  delle	
  foto	
  presenti	
  nella	
  libreria,	
  allora	
  dovrà	
  cliccare	
  sul	
  pulsante	
  
“Scegli	
  foto”	
  che	
  aprirà	
  direttamente	
  la	
  libreria	
  fotografica	
  dell’Iphone.	
  




                                          	
     Figura	
  29:	
  Libreria	
  fotografica	
  

Altrimenti,	
   se	
   vorrà	
   scattare	
   una	
   foto	
   nuova,	
   dovrà	
   premere	
   il	
   pulsante	
   “Click	
   foto!”	
   che	
   andrà	
  
direttamente	
  a	
  comandare	
  la	
  fotocamera.	
  




       	
                                                                                                                                           5-­‐107	
  
5.4 Distribuzione	
  e	
  visualizzazione	
  dei	
  punti	
  d’interesse	
  sulla	
  mappa	
  
Dalla	
   maschera	
   principale	
   di	
   visualizzazione	
   dei	
   dati	
   memorizzati	
   (figura	
   27),	
   l’utente,	
   per	
   accedere	
  
alla	
  mappa,	
  dovrà	
  premere	
  il	
  pulsante	
  “Map”;	
  alla	
  fine	
  del	
  suo	
  caricamento,	
  potrà	
  visualizzarvi	
  i	
  punti	
  
d’interesse,	
   sia	
   quelli	
   memorizzati	
   internamente	
   al	
   telefono	
   sia	
   quelli	
   scaricati	
   dal	
   web	
   service.	
   Essi	
  
saranno	
  identificati	
  tramite	
  dei	
  “pin”	
  di	
  colore	
  verde	
  che	
  saranno	
  sviluppati	
  in	
  modo	
  tale	
  che	
  quando	
  
l’utente	
  ci	
  cliccherà	
  sopra,	
  potrà	
  visualizzare	
  le	
  informazioni	
  riguardanti	
  il	
  loro	
  nome	
  e	
  la	
  descrizione.	
  




                                                                                                                               	
  
Figura	
  30:	
  Visualizzazione	
  della	
  mappa	
  e	
  delle	
  informazioni	
  di	
  un	
  punto	
  d'interesse	
  

	
  

5.5 Collaudo	
  dell’”Augmented	
  Reality”	
  
L’utente,	
   trovandosi	
   nel	
   controller	
   dedicato	
   alla	
   visualizzazione	
   dei	
   dati	
   memorizzati	
   nella	
   memoria	
  
dell’Iphone,	
   per	
   accedere	
   alla	
   form	
   dedicata	
   all’implementazione	
   dell’Augmented	
   Reality,	
   dovrà	
   dal	
  
navigation	
  bar	
  premere	
  il	
  pulsante	
  “System	
  AR”.	
  

Nel	
  simulatore,	
  non	
  sarà	
  possibile	
  provare	
  in	
  maniera	
  diretta	
  queste	
  librerie	
  poiché	
  il	
  cuore	
  del	
  loro	
  
funzionamento	
   sarà	
   incentrato	
   sulla	
   gestione	
   della	
   fotocamera,	
   che	
   nell’Iphone	
   Simulator	
   non	
   riuscirà	
  
a	
   essere	
   emulata	
   in	
   maniera	
   perfetta.	
   Per	
   evitare	
   quindi	
   di	
   mandare	
   in	
   crash	
   il	
   sistema,	
   si	
   sono	
  
aggiunte	
  delle	
  verifiche	
  per	
  far	
  capire	
  all’applicativo	
  stesso	
  se	
  si	
  trova	
  sul	
  simulatore	
  oppure	
  installato	
  
sul	
  dispositivo.	
  

In	
   sostanza,	
   il	
   controller	
   non	
   potendo	
   sfruttare	
   la	
   fotocamera	
   integrata,	
   non	
   inizializzerà	
   gli	
   oggetti	
  
dedicati	
   alla	
   gestione	
   della	
   stessa,	
   ma	
   visualizzerà	
   solamente	
   i	
   punti	
   d’interesse	
   che	
   saranno	
   visibili	
  
ipotizzando	
   che	
   l’utente	
   si	
   trovi	
   sulle	
   coordinate	
   WGS84	
   di	
   Cupertino	
   e	
   con	
   un	
   determinato	
   valore	
  
della	
  bussola,	
  entrambi	
  forniti	
  costantemente	
  dal	
  simulatore.	
  	
  

Il	
   risultato	
   dato	
   da	
   queste	
   routine	
   di	
   verifica	
   sarà	
   che	
   lo	
   sfondo	
   della	
   form,	
   così	
   vista	
   dall’utente	
   sul	
  
simulatore	
   sarà	
   bianco	
   (a	
   causa	
   dell’assenza	
   della	
   fotocamera),	
   mentre	
   verranno	
   comunque	
  
visualizzati	
  	
  i	
  punti	
  d’interesse	
  sullo	
  schermo	
  sfruttando	
  i	
  valori	
  delle	
  coordinate	
  GPS	
  e	
  della	
  bussola	
  
forniti	
  dall’emulatore.	
  	
  




       	
                                                                                                                                                           5-­‐108	
  
 
Figura	
  31:	
  Due	
  fasi	
  della	
  visualizzazione	
  dei	
  punti	
  d'interesse	
  tramite	
  l'Augmented	
  Reality	
  

	
  

5.6 Test	
  delle	
  funzionalità	
  di	
  navigazione	
  
L’utente,	
  trovandosi	
  nella	
  schermata	
  iniziale	
  (figura	
  27),	
  dovrà	
  posizionarsi	
  con	
  il	
  cursore	
  sul	
  tab	
  bar	
  e	
  
cliccare	
  sulla	
  scheda	
  nominata	
  “Route	
  Tracker”:	
  così	
  facendo	
  permetterà	
  al	
  programma	
  di	
  caricare	
  la	
  
mappa	
   e	
   a	
   caricamento	
   avvenuto,	
   l’utente	
   sarà	
   localizzato	
   tramite	
   un	
   pin,	
   attraverso	
   l’iterazione	
   del	
  
Mapkit	
  con	
  il	
  frame	
  work	
  CoreLocation.	
  

Se	
  l’utente	
  deciderà	
  di	
  registrare	
  il	
  percorso	
  da	
  lui	
  compiuto,	
  premerà	
  il	
  pulsante	
  “Start”:	
  il	
  programma	
  
a	
  questo	
  punto,	
  aumenterà	
  lo	
  zoom	
  sulla	
  regione	
  di	
  mappa,	
  dove	
  lui	
  si	
  troverà	
  e	
  la	
  ruoterà	
  sfruttando	
  
la	
  bussola	
  interna,	
  secondo	
  il	
  suo	
  angolo	
  di	
  vista.	
  

Va	
   ricordato	
   che	
   nel	
   collaudo	
   sul	
   simulatore,	
   non	
   tutte	
   le	
   operazioni	
   descritte	
   nel	
   codice	
   saranno	
  
eseguite	
  correttamente:	
  quando	
  l’utente	
  premerà	
  il	
  bottone	
  “Start”,	
  la	
  mappa	
  ruoterà	
  solo	
  inizialmente	
  
e	
  non	
  sarà	
  disegnato	
  il	
  percorso	
  poiché	
  il	
  funzionamento	
  del	
  ricevitore	
  GPS	
  e	
  della	
  bussola,	
  sarà	
  solo	
  
una	
  simulazione	
  che	
  fornirà	
  un	
  valore	
  costante.	
  

Quando	
  l’utente	
  attiverà	
  il	
  pulsante	
  “Start”,	
  esso	
  potrà	
  in	
  qualsiasi	
  momento	
  fermare	
  la	
  registrazione	
  
del	
   percorso,	
   tramite	
   lo	
   stesso	
   pulsante	
   che	
   cambierà	
   automaticamente	
   il	
   suo	
   nome	
   in	
   “Stop”	
   per	
  
ricordare	
   all’utilizzatore	
   del	
   programma	
   la	
   fine	
   della	
   registrazione.	
   Quando	
   lo	
   farà,	
   il	
   programma	
  
visualizzerà	
   i	
   dati	
   calcolati	
   e	
   resi	
   disponibili	
   dal	
   frame	
   work	
   tramite	
   una	
   finestra	
   di	
   dialogo	
   che	
  
avviserà	
  l’utente	
  della	
  velocità	
  media	
  e	
  della	
  distanza	
  del	
  percorso	
  compiuto.	
  

Nel	
   caso	
   del	
   test	
   su	
   simulatore,	
   i	
   valori	
   di	
   velocità	
   e	
   distanza	
   percorsi	
   saranno	
   pari	
   a	
   zero,	
   poiché	
  
secondo	
   il	
   programma	
   l’utente	
   sarà	
   costantemente	
   fermo,	
   com’è	
   mostrato	
   nella	
   seconda	
   parte	
   della	
  
figura	
  sottostante.	
  

	
  




       	
                                                                                                                                                        5-­‐109	
  
 




                                                                                                                      	
  
	
  Figura	
  32:	
  Simulazione	
  del	
  modulo	
  di	
  navigazione	
  

	
  


6 CONCLUSIONI	
  
	
  
Il	
   progetto	
   sviluppato	
   in	
   questa	
   tesi	
   è	
   da	
   considerarsi	
   come	
   prototipo	
   per	
   lo	
   studio	
   e	
  
l’implementazione	
  pratica	
  del	
  problema	
  dell’”Augmented	
  Reality”	
  sviluppato	
  su	
  piattaforma	
  Iphone.	
  

Esso	
   è	
   stato	
   elaborato	
   partendo	
   dall’ipotesi	
   che	
   si	
   doveva	
   ottenere	
   un	
   programma	
   in	
   grado	
   di	
  
riconoscere	
  tramite	
  il	
  sensore	
  della	
  fotocamera	
  gli	
  oggetti	
  circostanti,	
  partendo	
  dall’idea	
  che	
  l’utente	
  
stesso	
  si	
  dovesse	
  trovare	
  “immerso”	
  in	
  quel	
  determinato	
  ambiente	
  .	
  	
  

       	
                                                                                                                                    6-­‐110	
  
Alla	
   fine,	
   quindi	
   si	
   è	
   ottenuto	
   un	
   programma	
   in	
   grado	
   di	
   risolvere	
   questo	
   problema,	
   implementando	
   le	
  
librerie	
   chiamate	
   ”Iphone	
   ARKit”	
   e	
   facendole	
   interagire	
   con	
   un	
   database	
   interno	
   per	
   i	
   POI	
   (punti	
  
d’interesse)	
  personali	
  dell’utente	
  e	
  con	
  un	
  web	
  service	
  per	
  i	
  punti	
  disponibili	
  su	
  un	
  database	
  remoto,	
  
con	
  lo	
  scopo	
  poi	
  di	
  elaborarli	
  successivamente	
  ad	
  esempio	
  per	
  la	
  loro	
  localizzazione	
  su	
  una	
  mappa.	
  

In	
   un	
   secondo	
   momento,	
   si	
   è	
   deciso	
   di	
   aggiungere	
   all’applicativo	
   finora	
   sviluppato	
   delle	
   elementari	
  
funzioni	
   di	
   navigazione,	
   tenendo	
   presente	
   sempre	
   che	
   il	
   programma	
   doveva	
   rispettare	
   dei	
   vincoli	
   di	
  
leggerezza	
  nei	
  caricamenti	
  dati:	
  si	
  è	
  stabilito	
  quindi	
  che	
  le	
  mappe	
  necessarie	
  alla	
  navigazione	
  fossero	
  
quelle	
  disponibili	
  direttamente	
  dalla	
  rete	
  (nel	
  caso	
  di	
  questo	
  programma,	
  quelle	
  di	
  Google	
  Maps®)	
  e	
  
che	
   l’utente	
   potesse	
   inoltre	
   tracciare	
   sulle	
   stesse,	
   il	
   percorso	
   compiuto	
   dal	
   dispositivo	
   in	
   un	
  
determinato	
  tempo.	
  

6.1 Pregi	
  e	
  difetti	
  individuati	
  nel	
  programma	
  
6.1.1 Pregi	
  
Per	
   quanto	
   concerne	
   i	
   pregi	
   di	
   questo	
   programma	
   descritto,	
   si	
   capisce	
   che	
   può	
   essere	
   adattabile	
   e	
  
integrabile	
  per	
  svariati	
  scopi:	
  lo	
  sviluppatore	
  potrà	
  quindi	
  decidere	
  ad	
  esempio	
  quali	
  dati	
  utili	
  estrarre	
  
dalla	
  memoria	
  del	
  dispositivo	
  o	
  dal	
  web	
  service	
  utilizzato	
  e	
  adattare	
  l’interfaccia	
  grafica	
  ai	
  suoi	
  scopi,	
  
soprattutto	
  nella	
  parte	
  riguardante	
  l’”Augmented	
  Reality”.	
  

Dalla	
   parte	
   invece	
   del	
   cliente	
   che	
   utilizzerà	
   il	
   programma,	
   sarà	
   evidente	
   la	
   semplificazione	
   nel	
  
caricamento	
   delle	
   mappe	
   nelle	
   interfacce	
   grafiche	
   in	
   quanto,	
   non	
   sarà	
   richiesta	
   la	
   memorizzazione	
  
delle	
  stesse	
  nella	
  memoria	
  del	
  telefono,	
  ma	
  il	
  tutto	
  sarà	
  delegato	
  alla	
  rete.	
  	
  

I	
   dati	
   utilizzati	
   nell’AR,	
   inoltre	
   saranno	
   molto	
   utili	
   per	
   un	
   utilizzo	
   sul	
   campo	
   dell’applicazione	
   stessa	
  
come	
   uno	
   strumento	
   aggiuntivo	
   di	
   navigazione,	
   per	
   l’individuazione	
   di	
   determinati	
   tipi	
   di	
   punti	
  
d’interesse	
  scelti	
  a	
  priori	
  dallo	
  sviluppatore.	
  

6.1.2 Difetti	
  
I	
  difetti	
  riscontrati	
  alla	
  fine	
  della	
  realizzazione	
  del	
  progetto,	
  possono	
  essere	
  sintetizzati	
  in	
  tre	
  punti:	
  

      1. L’impossibilità	
  di	
  trasferire	
  i	
  dati	
  memorizzati	
  su	
  un	
  altro	
  Iphone	
  
      2. La	
  dipendenza	
  del	
  programma	
  dal	
  collegamento	
  ad	
  internet	
  
      3. Il	
  consumo	
  eccessivo	
  della	
  batteria	
  

Il	
  primo	
  è	
  un	
  difetto	
  importante	
  poiché	
  grazie	
  a	
  questo,	
  non	
  è	
  possibile	
  realizzare	
  un’implementazione	
  
dello	
  stesso	
  software	
  contenente	
  gli	
  stessi	
  dati	
  su	
  molteplici	
  dispositivi.	
  Esso	
  quindi	
  fino	
  a	
  quando	
  non	
  
verrà	
  risolto,	
  sarà	
  da	
  considerarsi	
  come	
  la	
  principale	
  mancanza	
  di	
  questo	
  programma	
  che	
  potrà	
  altresì	
  
essere	
  usato	
  come	
  una	
  sorta	
  di	
  guida	
  individuale	
  dell’utente.	
  	
  

Il	
  secondo	
  sarà	
  considerato	
  una	
  carenza	
  marginale	
  in	
  quanto	
  limiterà	
  il	
  funzionamento	
  dell’applicativo	
  
in	
  maniera	
  parziale:	
  le	
  funzioni	
  quindi	
  disabilitate	
  saranno	
  quelle	
  del	
  caricamento	
  dei	
  punti	
  d’interesse	
  
prelevati	
  dal	
  web	
  service	
  e	
  i	
  caricamenti	
  delle	
  mappe	
  che	
  come	
  già	
  scritto	
  saranno	
  delegate	
  ad	
  
internet,	
  mentre	
  la	
  parte	
  riguardante	
  l’”Augmented	
  Reality”	
  funzionerà	
  ugualmente.	
  

Il	
  terzo	
  problema,	
  al	
  contrario	
  non	
  potrà	
  essere	
  risolto	
  dal	
  programmatore,	
  ma	
  dovrà	
  essere	
  appianato	
  
dal	
  costruttore,	
  perché	
  questo	
  programma	
  richiedendo	
  l’accesso	
  alla	
  rete	
  e	
  al	
  GPS,	
  esigerà	
  una	
  
notevole	
  quantità	
  di	
  corrente	
  che	
  conseguentemente	
  farà	
  diminuire	
  l’autonomia	
  del	
  telefono.	
  

6.1.3 Sviluppi	
  futuri	
  
Essendo	
  questo	
  progetto	
  un	
  prototipo	
  che	
  implementa	
  l’”Augmented	
  Reality”,	
  su	
  questa	
  base	
  potrà	
  
essere	
  realizzato	
  un	
  programma	
  che	
  permetterà	
  all’utente	
  di	
  utilizzare	
  più	
  web	
  services	
  assieme	
  
poiché	
  al	
  momento	
  attuale,	
  se	
  ne	
  è	
  implementato	
  solamente	
  uno	
  singolo.	
  

Scegliendo	
  quindi	
  d’implementare	
  più	
  servizi,	
  si	
  darà	
  l’opportunità	
  all’utente	
  di	
  possedere	
  uno	
  
strumento	
  ancora	
  più	
  ricco	
  d’informazioni	
  utili	
  nella	
  navigazione	
  e	
  quindi	
  per	
  il	
  caricamento	
  di	
  nuovi	
  
punti	
  sia	
  nell’AR,	
  sia	
  sulle	
  mappe.	
  	
  
      	
                                                                                                                                                 6-­‐111	
  
Inoltre,	
  per	
  rendere	
  disponibili	
  gli	
  stessi	
  punti	
  sulla	
  memoria	
  interna	
  di	
  molteplici	
  Iphone,	
  potrà	
  essere	
  
sviluppato	
  separatamente	
  al	
  programma,	
  un	
  server,	
  nel	
  quale	
  saranno	
  memorizzati	
  i	
  punti	
  da	
  inserire	
  
in	
  memoria	
  dei	
  telefoni,	
  sempre	
  nell’ipotesi	
  che	
  gli	
  stessi	
  siano	
  utilizzati	
  da	
  un	
  ente	
  come,	
  ad	
  esempio,	
  
“guide	
  turistiche”	
  di	
  una	
  determinata	
  località.	
  




     	
                                                                                                                                           6-­‐112	
  
7 BIBLIOGRAFIA	
  
	
  
Per	
  lo	
  sviluppo	
  di	
  questo	
  progetto,	
  i	
  documenti	
  che	
  sono	
  stati	
  utili,	
  sono	
  stati	
  quelli	
  del	
  portale	
  della	
  
Apple	
  per	
  gli	
  sviluppatori,	
  posto	
  all’indirizzo	
  	
  

http://developer.apple.com/iphone/index.action	
  

Dove	
  il	
  programmatore	
  può	
  trovare	
  tutti	
  i	
  tutorial	
  necessari	
  all’apprendimento	
  dell’Objective	
  C	
  e	
  delle	
  
guide	
  utili	
  allo	
  sviluppo	
  di	
  programmi	
  funzionanti.	
  

Da	
   segnalare	
   inoltre	
   un	
   altro	
   sito	
   internet	
   molto	
   utile,	
   in	
   cui	
   sono	
   disponibili	
   delle	
   lezioni	
   on	
   line	
   sulle	
  
basi	
  di	
  programmazione	
  dell’Objective	
  C,	
  redatte	
  dall’Università	
  di	
  Stanford	
  e	
  reperibili	
  all’indirizzo	
  	
  

http://www.stanford.edu/class/cs193p/cgi-­bin/drupal/downloads-­2010-­winter	
  

Mentre	
  per	
  quanto	
  riguarda	
  la	
  trattazione	
  di	
  singoli	
  problemi,	
  attraverso	
  articoli	
  scritti	
  direttamente	
  
da	
  sviluppatori	
  indipendenti,	
  per	
  la	
  programmazione	
  su	
  Iphone,	
  bisogna	
  segnalare	
  questo	
  sito	
  	
  

http://icodeblog.com/	
  


8 RINGRAZIAMENTI	
  
	
  
Per	
   il	
   lavoro	
   svolto,	
   devo	
   innanzitutto	
   ringraziare	
   il	
   professor	
   Giorgio	
   Manzoni,	
   per	
   avermi	
   dato	
   la	
  
possibilità	
   di	
   realizzare	
   un	
   suo	
   progetto,	
   la	
   professoressa	
   Raffaela	
   Cefalo	
   invece	
   per	
   avermi	
   fatto	
  
conoscere	
  le	
  materie	
  riguardanti	
  la	
  topografia	
  e	
  dato	
  un	
  supporto	
  per	
  lo	
  svolgimento	
  della	
  tesi	
  e	
  del	
  
tirocinio,	
   Sara,	
   una	
   persona	
   che	
   mi	
   è	
   stata	
   vicina	
   negli	
   ultimi	
   2	
   anni,	
   in	
   particolare	
   in	
   questo	
  
interminabile	
   periodo,	
   i	
   genitori	
   per	
   avermi	
   dato	
   la	
   possibilità	
   di	
   frequentare	
   l’università	
   e	
   anche	
   di	
  
terminarla.	
  

Un	
  saluto	
  va	
  anche	
  ai	
  miei	
  nonni	
  che	
  non	
  ci	
  sono	
  più,	
  in	
  particolare	
  a	
  nonno	
  Alberto	
  appassionato	
  di	
  
informatica	
  che	
  ha	
  visto	
  l’inizio	
  della	
  mia	
  carriera	
  universitaria,	
  ma	
  non	
  la	
  fine.	
  




       	
                                                                                                                                                              8-­‐113	
  

Tesi

  • 1.
      UNIVERSITA’  DEGLI  STUDI  DI  TRIESTE   Facoltà  di  Ingegneria   Corso  di  Laurea  specialistica  in  Ingegneria  Informatica   Anno  Accademico  2009/2010     IMPLEMENTAZIONE  DI  UN  APPLICATIVO  DI  AR   (Augmented  Reality)  SU  DISPOSITIVO  IPHONE  PER   IL  RICONOSCIMENTO  E  LA  LOCALIZZAZIONE  DI   PUNTI  D’INTERESSE     Relatore:  Prof.ssa  Raffaela  Cefalo   Correlatore:  Prof.  Giorgio  Manzoni       Laureando:  Michele  Verani        
  • 2.
        I  computer  sono  incredibilmente  veloci,  accurati  e  stupidi.  Gli  uomini  sono  incredibilmente  lenti,   inaccurati  e  intelligenti.  Insieme  sono  una  potenza  che  supera  l'immaginazione.    –  Albert  Einstein     1-­‐2  
  • 3.
      Sommario   1  PREMESSA   1-­5   1.1   BREVE  DESCRIZIONE  DEL  LAVORO  SVOLTO   1-­5   1.2   SUDDIVISIONE  DELLO  SVILUPPO  DELLA  TESI   1-­5   2   INTRODUZIONE   2-­5   2.1   SISTEMA  OPERATIVO  IPHONE  OS   2-­5   2.1.1   STRUTTURA  DEL  SISTEMA  OPERATIVO  IPHONE  OS   2-­‐6   2.2   STRUMENTI  DI  SVILUPPO  DISPONIBILI  PER  L’IPHONE   2-­10   2.2.1   IL  FRAME  WORK  COCOA   2-­‐10   2.2.2   LA  PIATTAFORMA  SDK   2-­‐11   2.2.3   XCODE   2-­‐11   2.2.4   INTERFACE  BUILDER   2-­‐12   2.2.5   IPHONE  OS  SIMULATOR   2-­‐14   2.3   OBJECTIVE-­C   2-­14   2.3.1   OGGETTI,  CLASSI,  METODI  E  ISTANZE   2-­‐14   2.3.2   INTERFACCE  E  IMPLEMENTAZIONI   2-­‐14   2.3.3   MESSAGGI  E  POLIMORFISMO   2-­‐16   2.3.4   OBJECTIVE-­‐C  E  OGGETTI  COCOA   2-­‐16   2.3.5   DINAMICITÀ  DELL’OBJECTIVE-­‐C   2-­‐16   2.3.6   LE  CLASSI  ROOT   2-­‐17   2.3.7   ALLOCAZIONE  E  RILASCIO  DEGLI  OGGETTI   2-­‐18   2.3.8   INTROSPECTION   2-­‐21   2.3.9   OGGETTI  MODIFICABILI   2-­‐21   2.3.10   RAGGRUPPAMENTI  DI  CLASSI   2-­‐22   3   PROGETTAZIONE   3-­22   3.1   DEFINIZIONE  DELL’OBIETTIVO   3-­23   3.2   ANALISI  DEI  PROBLEMI  GENERICI   3-­23   3.3   SCOMPOSIZIONE  DELLE  SINGOLE  PROBLEMATICHE   3-­23   3.3.1   GESTIONE  DEL  FRAME  WORK  CORELOCATION   3-­‐24   3.3.2   GESTIONE  DELL’UIACCELEROMETER   3-­‐27   3.3.3   GESTIONE  DELLA  FOTOCAMERA   3-­‐28   3.3.4   LA  MEMORIZZAZIONE  DEI  DATI   3-­‐29   3.3.5   USO  DEI  DATI  PROVENIENTI  DA  UN  WEB  SERVICE   3-­‐32   3.3.6   IL  FRAME  WORK  MAPKIT   3-­‐35   3.3.7   LA  LIBRERIA  DELL’”AUGMENTED  REALITY”(ARKIT)   3-­‐38   4   REALIZZAZIONE   4-­39   4.1   SPECIFICHE   4-­40   4.1.1   MEMORIZZAZIONE  PERSISTENTE  DEI  PUNTI  D’INTERESSE  E  INTEGRAZIONE  NEL  PROGRAMMA  DELL’USO  DELLA   FOTOCAMERA   4-­‐40   4.1.2   IMPLEMENTAZIONE  DELL’AUGMENTED  REALITY  (ARKIT)   4-­‐71   4.1.3   L’UTILIZZO  DEI  WEB  SERVICES  NELL’APPLICAZIONE   4-­‐75   4.1.4   DEFINIZIONE  DELLE  FUNZIONI  TIPICHE  DEI  SOFTWARE  DI  NAVIGAZIONE   4-­‐88   4.2   LO  SVILUPPO  DEL  PROGRAMMA  COMPLETO   4-­101     1-­‐3  
  • 4.
    5   COLLAUDO   5-­105   5.1   COLLAUDO  SULL’IPHONE  SIMULATOR   5-­106   5.2   VISUALIZZAZIONE  DEI  PUNTI  D’INTERESSE   5-­106   5.3   INSERIMENTO  MANUALE  DEI  PUNTI  D’INTERESSE  DELL’UTENTE   5-­107   5.4   DISTRIBUZIONE  E  VISUALIZZAZIONE  DEI  PUNTI  D’INTERESSE  SULLA  MAPPA   5-­108   5.5   COLLAUDO  DELL’”AUGMENTED  REALITY”   5-­108   5.6   TEST  DELLE  FUNZIONALITÀ  DI  NAVIGAZIONE   5-­109   6   CONCLUSIONI   6-­110   6.1   PREGI  E  DIFETTI  INDIVIDUATI  NEL  PROGRAMMA   6-­111   6.1.1   PREGI   6-­‐111   6.1.2   DIFETTI   6-­‐111   6.1.3   SVILUPPI  FUTURI   6-­‐111   7   BIBLIOGRAFIA   7-­113   8   RINGRAZIAMENTI   8-­113       1-­‐4  
  • 5.
    1 PREMESSA     1.1 Breve  descrizione  del  lavoro  svolto   L’obiettivo  di  questo  progetto  è  lo  sviluppo  di  un  programma  per  Iphone  che  coniuga  le  funzionalità   fornite  dalla  libreria  dell’“Augmented  Reality”(ARKit  for  Iphone)  con  le  caratteristiche  disponibili  in   un  generico  software  di  navigazione,  quali  la  geo  localizzazione  dell’utente  e  l’individuazione  sulla   mappa  dei  punti  d’interesse  disponibili  nella  memoria  del  telefono  e  quelli  scaricati  dalla  rete,   fornendo  inoltre  la  possibilità  di  inserire  delle  informazioni  aggiuntive  nella  descrizione  di  ogni  punto,   sia  di  tipo  visivo,  come  le  foto,  che  di  tipo  testuale.   Per  descrivere  in  maniera  esaustiva  questo  progetto,  la  trattazione  è  stata  divisa  in  più  capitoli  nei   quali  sono  state  affrontate  le  singole  problematiche  e  soluzioni  adottate  in  corso  d'opera  durante   l'elaborazione  del  lavoro  finale.   1.2 Suddivisione  dello  sviluppo  della  tesi   Il  lavoro  di  tesi  è  stato  suddiviso  in  sei  capitoli,  ciascuno  dei  quali  tratta  in  maniera  specifica  le  fasi  di   lavoro  svolte  durante  lo  sviluppo  della  tesi:     1. Premessa   2. Introduzione   3. Progettazione   4. Realizzazione   5. Collaudo   6. Conclusioni     Nell’introduzione  è  stata  fatta  una  descrizione  della  struttura  hardware  e  logica  dell’Iphone  usato  per   lo   sviluppo   della   tesi,   andando   a   descrivere   le   librerie   e   i   frameworks   implementati   al   suo   interno,   passando   poi   alla   descrizione   del   tool   di   sviluppo   adottato   e   a   un’analisi   del   linguaggio   usato   per   la   realizzazione  del  programma  richiesto.   Nella  progettazione  si  sono  trattate  le  problematiche  riguardanti  lo  sviluppo  del  programma,  partendo   dall’analisi   dell’utilizzo   dei   frame   work   CoreLocation   e   Mapkit,   passando   poi   ai   problemi   della   memorizzazione  dei  punti  d’interesse  e  l’iterazione  del  sistema  con  i  web  services,  finendo  poi  con  una   descrizione  dettagliata  della  gestione  delle  librerie  dell’”Augmented  Reality”.   Si   è   passati   poi   alla   descrizione   della   fase   operativa,   ossia   la   parte   della   realizzazione   dei   moduli   necessari   al   funzionamento   del   programma,   tenendo   conto   delle   specifiche   iniziali   del   progetto   ed   esponendo  in  maniera  completa  l’implementazione  dell’applicativo.   Nel   penultimo   capitolo   è   stato   trattato   il   collaudo   del   programma   sul   simulatore,  con   l’effettuazione   di   un’analisi   del   funzionamento   dettagliato   delle   varie   parti   dell’applicativo   e   con   una   prova   complessiva   del  programma  richiesto.     Nell’ultimo  capitolo  si  è  cercato  invece  di  analizzare  in  maniera  obiettiva  il  progetto,  trovando  i  suoi   eventuali  pregi  e  difetti  ed  esplicando  in  maniera  sintetica  gli  sviluppi  futuri  ipotizzati  per  migliorarlo.   2 INTRODUZIONE     2.1 Sistema  operativo  Iphone  OS   Negli   ultimi   decenni   i   dispositivi   mobili   hanno   conquistato   fette   di   mercato   sempre   più   rilevanti   andando  di  pari  passo  con  l'incremento  delle  funzionalità  avvenuto  tra  i  primi  e  gli  ultimi  modelli  nati.   Con   lo   sviluppo   di   hardware   sempre   più   sofisticati   è   stato   possibile   quindi   fornire   tali   dispositivi   di   caratteristiche   anche   complesse,   come   il   riconoscimento   da   parte   del   sistema   di   file   musicali,   di     2-­‐5  
  • 6.
    riproduzione  di  video,  del  collegamento  ad  internet  tramite  rete  Wi-­‐Fi  e  dell'acquisizione,  tramite  un   ricevitore  interno,  del  segnale  GPS,  consentendo  la  geo-­‐localizzazione  dell'utente.     Essendo   prodotti   così   versatili,   è   intuibile   quanto   siano   diventati   presenti   nelle   abitudini   dei   consumatori   e   abbiano   di   conseguenza   indirizzato   i   produttori   stessi   ad   attuare   e   sviluppare   innovative   scelte   commerciali.   Di   conseguenza,   quindi,   con   il   crescere   delle   prestazioni   hardware,   infatti,   sono   cresciuti   anche   gli   investimenti   nella   progettazione   di   software   che   li   sfrutta,   ma   nonostante  ciò,  i  sistemi  operativi  nati  per  girare  in  questi  ambienti,  devono  comunque  far  fronte  alle   carenze   hardware   che   tali   dispositivi   hanno   rispetto   alle   macchine   tradizionali,   oltre   a   dover   gestire   interfacce  utente  notevolmente  semplificate,  considerando  gli  schermi  di  ridotte  dimensioni.       L'iPhone   è   un   prodotto   orientato   al   mercato   consumer   non   avendo   quindi   un   target   di   tipo   business;   i   suoi   punti   di   forza   sono   la   facilità   d'uso,   l'estetica   e   l'usabilità   nella   navigazione   in   internet,   oltre  ad   avere  una  suite  completa  di  programmi  per  l'ufficio.   L'innovazione  che  ha  portato  nel  settore  è  sicuramente  dovuta  alle  sue  caratteristiche  hardware,  ma   anche   alla   sua   usabilità,   superiore   a   tutti   i   suoi   predecessori.   In   definitiva   è   la   sintesi   di   un   dispositivo   di  elevato  design,  supportato  da  un  sistema  operativo  semplificato  che  deriva  dal  Mac  OS  X,  il  sistema   Apple   per   computer   Desktop,   ricalcando   abbastanza   fedelmente   la   struttura   che   si   trova   sugli   Apple   ma   comunque   differenziandosi   da   questi   per   l’implementazione   di   un'interfaccia   grafica   molto   semplificata.     2.1.1 Struttura  del  sistema  operativo  Iphone  OS   Apple  inc.  ha  fatto  il  suo  ingresso  nei  dispositivi  mobili  nel  2007  con  una  prima  versione  dell'iPhone,   successivamente   nel   luglio   del   2008   è   stato   presentato   un   secondo   modello   disponibile   in   molti   più   Paesi.   Come  tutti  gli  altri  prodotti  Apple,  anche  con  l'iPhone,  la  casa  produttrice  ha  deciso  di  legare  il  sistema   operativo   ad   un   unico   dispositivo   hardware,   a   differenza   quindi   dei   suoi   concorrenti,   i   quali   invece   sono/possono   essere   installati   su   dispositivi   diversi,   sia   in   architettura   che   nel   produttore.(vedi   il   sistema  operativo  Android  e  Windows  Mobile).   L'iPhone   OS   invece,   non   ha   previsto   la   portabilità   della   sua   logica   su   altri   telefoni   ed   è   direttamente   derivato  dal  sistema  operativo  già  utilizzato  in  ambiente  desktop.     2.1.1.1 Descrizione  della  logica  dell’Iphone  OS       Figura  1:  struttura  logica  del  sistema  operativo   Come  si  vede  dalla  figura  1,    il  sistema  Iphone  OS  è  organizzato  per  strati,  ognuno  dei  quali  dipendente   da  quello  sottostante  ma  che  gestisce  servizi  e  periferiche    diverse.     2-­‐6  
  • 7.
    Il  sistema,  sotto  lo  strato  dell’applicazione  (application  layer)  è  strutturato  nella  seguente  maniera:   • Application  Frameworks  in  cui  è  contenuto  l’UIKit   • Lo  strato  riguardante  la  gestione  dell’audio  e  della  grafica   • Core  Frameworks  in  cui  è  contenuto  il  Foundation   • Lo  strato  Core  OS  (ovvero  il  Kernel  del  sistema)       2.1.1.1.1 Application  Frameworks   E’  lo  strato  che  racchiude  uno  dei  frame  work  più  utilizzati  nella  programmazione  in  Objective-­‐C:     ⇒ UIKit   Esso   è   uno   dei   più   usati   perché   fornisce   gli   oggetti   che   le   applicazioni   mostrano   nell'interfaccia   utente   e  definisce  la  struttura  per  il  comportamento  della  nostra  applicazione,  inclusa  la  gestione  degli  eventi,   curando  anche  la  gestione  dei  sensori  implementati  all'interno  del  telefono  stesso,  quali  ad  esempio  il   ricevitore  GPS,  il  magnetometro  (presente  nella  versione  3GS)  e  l'accelerometro.     L’interfaccia  grafica  dell’applicazione,  quindi  può  essere  sviluppata  in  tre  modi  differenti:   1) Sfruttando  l’Object  Library  posto  nell’Interface  Builder;   2) Costruendo  gli  oggetti  attraverso  la  disposizione  e  la  programmazione  in  un  frame  work;   3) Implementando   gli   oggetti   delle   interfacce   utente   attraverso   sottoclassi   della   classe   madre   UIView.     Una  delle  caratteristiche,  che  differenziano  questi  oggetti  grafici  con  quelli  implementati  nel  MAC  OS  X   sono  le  dimensioni  dei  singoli  componenti:  necessitano  di  essere  adeguate  allo  schermo  dell’Iphone  ed   all’uso  delle  dita  da  parte  dell’utente  sul  display  del  telefono.   In  UIKit,  le  classi  degli  oggetti  grafici  possono  essere  divise  nei  seguenti  gruppi:   1) Controlli   2) Modal  views   3) Scroll  views  (implementazione  delle  view  di  tabelle,  testo  e  web)   4) Toolbar,  navigation  bar  e  view  controller     Per   quanto   riguarda   il   primo   tipo,   gli   oggetti   che   ne   fanno   parte   sono   quelli   derivanti   dalle   classi   UIControl  che  comprendono  gli  UIButton  (pulsanti),  gli  UISwitch(quelli  che  simulano  lo  switch  on/off),   e  quelli  che  riguardano  la  selezione  di  gruppi  multidimensionali  (UIPickerView)  e  l'UIPageControl.   Per  il  gruppo  modal  view,  appartengono  le  classi  UIActionSheet  ed  UIAlertView,  ereditate  ambedue  da   UIModalView.   La   prima   visualizzerà   i   messaggi   all'utente   sotto   forma   di   fogli   allegati   oppure   viste   speciali,  mentre  la  seconda  sotto  forma  di  messaggi  di  tipo  “alert”.     Apparterrà  all’ultimo  gruppo,  la  classe  dell’UIViewController,  che  fornisce  metodi  gestire  in  generale  le   “view”,   i   messaggi   di   warning   della   gestione   della   memoria   dell'applicazione   oppure   proprio   per   coordinare  le  toolbar  e  le  navigation  bar.     2.1.1.1.2 Graphics  e  Audio   ⇒ Graphics   E'   uno   degli   elementi   più   importanti   nello   sviluppo   di   un'applicazione,   perché   consente   all'utente   di   interagire  con  il  sistema,  permettendo  al  programmatore  di  sfruttare  immagini,  view  e  funzioni  fornite   dal  framework  UIKit  proprio  per  migliorare  l'interfaccia  utente  dell'applicazione  sviluppata.       2-­‐7  
  • 8.
    Inoltre,   grazie   a   questa   gestione,   ha   la   possibilità   di   creare   degli   elementi   personalizzabili   con   dei   framework  supplementari  resi  accessibili  dal  tool  di  sviluppo:     1. QuartzCore.framework   2. OpenGLES.framework   3. CoreGraphics.framework     1. Il   QuartzCore   frame   work   fornisce   lo   sviluppatore   di   un'interfaccia   di   alto   livello   per   la   creazione   di   animazioni   personalizzate   che   sono   concepite   attraverso   l’adozione   delle   interfacce  di  CoreAnimation.     2. Il   frame   work   OpenGL   ES   si   basa   sulle   specifiche   OpenGL   ES   v1.1   e   fornisce   strumenti   per   il   disegno   di   contenuti   2D   e   3D.   È   un   frame   work   scritto   in   C   che   lavora   a   stretto   contatto   con   l'hardware  per  fornire  un  elevato  frame  rate,  fondamentale  nello  sviluppo  di  giochi.   3. Si  tratta  dello  stesso  frame  work  utilizzato  per  il  disegno  in  Mac  OS  X,  anche  se  in  questo  caso  è   usato   nell'Iphone   OS.   Anche   in   quest’ambiente,   comunque   è   implementato   per   la   rappresentazione  di  oggetti  grafici,  semplificando  il  riutilizzo  dei  contenuti  dell’interfaccia.     ⇒ Audio     Per  quanto  riguarda  questo  sotto  strato,  possiamo  distinguere  i  seguenti  tipi  di  frame  work:     1. CoreAudio.framework   2. AudioToolbox.framework   3. AudioUnit.framework   4. OpenAL     1. CoreAudio.framework   fornisce   informazioni   sulle   caratteristiche   e   sul   formato   audio   del   file,   fornendo  servizi  di  riproduzione  e  registrazione  per  file  e  flussi  audio.     2. Audio   Toolbox   fornisce   servizi   di   riproduzione   e   registrazione   per   file   e   flussi   audio.   Questo   frame  work  prevede  anche  il  supporto  per  la  gestione  di  file  audio  e  riproduzione  di  suoni  e   allarmi  di  sistema.   3. AudioUnit  fornisce  servizi  per  l'utilizzo  di  unità  audio  e  moduli  di  elaborazione.   4. Il   sistema   operativo   dell’Iphone   include   inoltre   anche   il   supporto   per   l’audio   Open   Library   (OpenAL)   che   è   uno   standard,   multi   piattaforma   per   la   gestione   3D   dell’audio   nelle   applicazioni.     2.1.1.1.3 Core  frameworks   Questo  livello  include  il  frame  work  Foundation  e  fornisce  i  servizi  (chiamato  anche  Core  Services)   necessari  a  tutte  le  applicazioni,  dall'accesso  dei  dati  dei  contatti(Address  book)  al  parsing  degli   elementi  XML(con  l'utilizzo  dell'NSXMLParser).     ⇒ Foundation     Questo  frame  work  in  pratica  definisce  un  insieme  di  classi  che  possono  essere  usate  per  ogni  tipo  di   software   Cocoa,   fornendo   i   comportamenti   base   degli   oggetti,   i   meccanismi   per   la   loro   gestione   e   definendo   gli   oggetti   per   i   tipi   di   dati   primitivi,   collezioni   e   servizi   del   sistema   operativo:   potrebbe   essere  considerato  come  un  wrapper  ad  oggetti  del  frame  work  Core  Foundation.   Un   oggetto   per   potersi   definire   appartenente   a   Foundation   deve   derivare   dalla   “classe   madre”   NSObject   e   soprattutto   non   deve   essere   coinvolto   o   usato   esclusivamente   nell’interfaccia   utente   del   programma.     2-­‐8  
  • 9.
    Gli  scopi  per  cui  è  stato  pensato,  sono  molteplici,  tra  i  quali  spiccano  i  seguenti:     ⇒ Il  supporto  all'internazionalizzazione  e  alla  localizzazione  attraverso  le  stringhe  Unicode   ⇒ Il  supporto  alla  persistenza  di  dati  e  a  oggetti  distribuiti   ⇒ La  fornitura  di  misure  d’indipendenza  dal  sistema  operativo  orientato  alla  portabilità   ⇒ L’offerta   di   oggetti   wrapper   per   la   programmazione   e   definizione   di   primitive,   come   valori   numerici,   stringhe,   collection,   includendo   classi   per   l'accesso   ai   servizi   del   sistema,   quali   ad   esempio  porte,  thread  e  file  system     ⇒ Servizi  offerti     I  servizi  offerti  da  questo  strato  sono  elencati  qui  di  seguito:     1. Address  Book   2. Core  Foundation   3. Core  Location   4. CFNetwork   5. Security   6. SQLite  &  Core  Data   7. XML       1. Address   Book   consente   un   accesso   diretto   ai   dati   riguardanti   i   contatti   contenuti   nell'agenda   telefonica,  fornendo  una  completa  interfaccia  grafica  per  la  rappresentazione  dei  dati  richiesti,   attraverso  l'utilizzo  di  determinate  classi  dell’Objective-­‐C   2. Core   Foundation   è   un   insieme   d’interfacce   che   forniscono   la   gestione   dei   dati   di   base   e   dei   servizi  per  le  applicazioni  su  iPhone,  consentendo:   a) La  gestione  :   ⇒ Di  stringhe   ⇒ Delle  date  e  del  tempo   ⇒ Delle  preferenze   ⇒ Di  blocchi  di  dati  non  elaborati     b) Il  supporto  per:     ⇒ Tipi  di  dato  Collection   ⇒ La  manipolazione  di  stream  e  di  URL   ⇒ La  comunicazione  di  porte  e  processi   3. Core   Location   consente   di   stabilire   la   corretta   posizione   di   latitudine   e   longitudine   in   un   determinato   istante   dell'utente,   sfruttando   secondo   i   casi,   il   ricevitore   GPS,   la   triangolazione   delle  celle  o  le  informazioni  del  segnale  wi-­‐fi,  con  una  precisione  della  posizione  che  cambia   secondo  la  metodologia  utilizzata.   4. CFNetwork   è   un   set   di   interfacce   che   fornisce   astrazioni   orientate   ad   oggetti   per   gestire   i   protocolli   di   networking   che   aiutano   nel   controllo   dettagliato   sul   protocollo   dello   stack   e   facilitano   l'utilizzo   di   costrutti   di   basso   livello   come   i   socket   BSD,   con   lo   scopo   di   facilitare   i   compiti  di  comunicazione  via  FTP,  server  HTTP  e  la  risoluzione  di  host  DNS.   5.  Security   è   un   frame   work   che   offre   un’integrazione   alle   caratteristiche   già   esistenti   sulla   sicurezza   esplicitamente   dedicato   agli   sviluppatori   che   vogliano   aumentare   la   security   nella   gestione  dei  dati  nelle  applicazioni.     Tale   frame   work   fornisce   interfacce   per   gestire   certificati   a   chiave   pubblica   e   privata   e   politiche   di   sicurezza,   supportando   la   generazione   pseudo   casuale   di   numeri     2-­‐9  
  • 10.
    crittograficamente   sicuri   e   abilitando   il   salvataggio   di   certificati   e   chiavi   crittografate   nel   portachiavi  (keychen),  un  luogo  sicuro  per  salvare  dati  sensibili  degli  utenti.   6. SQLite   è   una   libreria   che   dà   la   possibilità   di   integrare   nell'applicazione   un   piccolo   database   SQL,   senza   dover   accedere   in   remoto   a   un’altra   base   di   dati,   consentendo   un   accesso   più   rapido  ai  record  delle  tabelle.   7. Core  Data  è  una  libreria  aggiunta  con  l'ultima  release  del  sistema  operativo  Iphone  OS  3.0  SDK.   Rispetto   alla   precedente,   offre   dei   vantaggi   in   termini   di   prestazioni   sulla   memorizzazione   dei   dati  in  tabelle.   Si  articola  in  tre  elementi:   ⇒ managed  object  models   ⇒ managed  object  contexts   ⇒ persistent  data  store     a. Un   “managed   object   model”   contiene   un   grafo   di   oggetti,   altresì   definito   come   una   “collezione”  di  oggetti  e  relazioni  uno  a  molti   b.  Il   “managed   object   context”   è   creato   con   lo   scopo   di   contenere   gli   oggetti   creati   da   entità  nel  “managed  object  model”  ed  è  costituito  da  un  “persistent  store  coordinator”   che  si  occupa  della  gestione  di  uno  o  più  sistemi  di  memorizzazione  persistente.   c. L'ultimo   elemento   invece   prende   il   nome   di   “persistent   data   store”   ed   è   quello   che   si   occupa   della   persistenza   della   memorizzazione   di   dati   creati   attraverso   il   “managed   object  context”.       8. Il   frame   work   Foundation   fornisce   la   classe   NSXMLParser   che   ci   permette   di   utilizzare   l’interfaccia  SAX  (Simple  API  for  XML),  con  lo  scopo  di  recuperare  elementi  da  un  documento   XML,   leggendo   il   file   XML   linea   per   linea   e   basando   la   sua   lettura   su   eventi.   Al   verificarsi   di   un   evento   (ad   esempio:   apertura   di   un   tag,   chiusura   di   un   tag,   etc…)   viene   chiamata  una  funzione  specifica  ,  chiamata  altresì  “handler”,  che  può  gestirlo.   I  vantaggi  dell’interfaccia  SAX  sono  principalmente  legati  alla  velocità  e  all’utilizzo  di  memoria   mentre   presenta   un   unico   difetto:   è   possibile   solamente   la   lettura   del   file   xml   e   non   la   sua   scrittura.     9. L'iPhone   OS,   in   questo   strato,   fornisce   un   insieme   di   interfacce   per   l'accesso   a   molte   funzionalità   di   basso   livello   del   sistema   operativo,   che   avvengono   attraverso   la   libreria   LibSystem.       2.2 Strumenti  di  sviluppo  disponibili  per  l’Iphone   2.2.1   Il  frame  work  Cocoa   Il  Cocoa,  racchiude  i  frame  work  più  usati  nell'implementazione  di  un  programma  per  l'Iphone:  UIKit  e   il   Foundation   permettono   un   accesso   da   parte   delle   applicazioni   agli   strati   sottostanti,   come   rappresentato   in   Fig   1,   poiché   tipicamente   esiste   sempre   un   metodo   UIKit   oppure   una   funzione   Foundation  corrispondente  per  una  chiamata  di  basso  livello.     Uno  dei  motivi  che  ha  consentito  la  sua  diffusione,  è  stato  la  sua  struttura  suddivisa  in:     ⇒ Un  ambiente  di  runtime   ⇒ Un  ambiente  di  sviluppo   A  runtime,  le  applicazioni  hanno  un'interfaccia  utente  ben  integrata  con  le  altre  parti  del  sistema  quali   il   Finder   e   il   Dock   ad   esempio,   come   anche   l'ambiente   di   sviluppo   che   presenta   al   programmatore   una   suite   integrata   di   parti   software   object-­‐oriented   che   permettono   di   creare   rapidamente   programmi   robusti   e   ricchi   di   caratteristiche,   grazie   al   riutilizzo,   alla   modifica   e   al   riadattamento   delle   classi   richieste  dall'applicativo.     2-­‐10  
  • 11.
    Apple   comunque   consiglia   sempre   l'utilizzo   delle   classi   e   degli   oggetti   forniti   dal   frame   work,   soprattutto  per  quanto  riguarda  l'approccio  alle  interfacce  grafiche.   2.2.1.1  Cocoa  nell’Iphone  OS   In  linea  generica,  si  può  dire  che  il  sistema  di  librerie  e  frame  work  dell'Iphone  OS  è  un  sottoinsieme   delle  librerie  e  dei  frame  work  di  Mac  OS-­‐X.  Le  caratteristiche  sulle  quali  si  differenziano  i  due  tipi  di   Cocoa   sono   poche,   ma   importanti:   tra   quelle   più   rilevanti,   spiccano   la   mancanza   della   riga   di   comando   per  accedere  ai  servizi  di  sistema  e  l'assenza  del  QuickTime  nella  piattaforma  mobile.   2.2.2     La  piattaforma  SDK   Con   l'introduzione   di   Xcode   3.1   e   dell'Iphone   OS,   si   è   anche   avuta   la   necessità   di   scegliere   la   piattaforma   sulla   quale   sviluppare   tutti   i   software,   appunto   la   SDK,   se   riferita   al   sistema   Mac   OS-­‐X   oppure  quella  riguardante  l'Iphone  OS.   L'SDK   per   l'Iphone   include   gli   stessi   componenti   dell'Sdk   del   Mac   OS-­‐X,   ma   si   differisce   da   essa   in   quanto   comprende   altri   tool   ed   un   compilatore   specifico   per   l'Iphone   OS   e   diversi   template   di   progetti   specifici  per  le  diverse  piattaforme.   2.2.3   Xcode   L'ambiente   di   sviluppo   per   applicazioni   Cocoa   non   è   unico,   è   possibile,   infatti,   sia   sviluppare   con   applicazioni  fornite  da  Apple,  come  Xcode  e  Interface  Builder,  sia  utilizzare  software  di  terze  parti.   Nonostante   ciò,   Xcode   e   Interface   Builder   sono   le   applicazioni   più   comunemente   utilizzate   per   sviluppare   software   Cocoa:   presentano   il   motore   dell'ambiente   di   sviluppo   integrato   (IDE)   per   applicazioni  in  Mac  OS  e  Iphone  OS.   Xcode   è   così   diffuso   perché   possiede   i   set   di   strumenti   di   sviluppo   più   completo   permettendo   di   gestire:   ⇒ La   creazione   dei   progetti,   indicando   l'SDK   richiesto,   i   requisiti   necessari,   le   dipendenze   e   le   configurazioni  strutturali.   ⇒ La  scrittura  del  codice  tramite  editor.   ⇒ La  compilazione  del  codice.   ⇒ Il  debug  del  progetto  in  maniera  remota  o  locale  sul  simulatore  dell'Iphone  OS     Permette   inoltre   di   compilare   progetti   da   codice   sorgente   scritto   in   C,   C++,   Objective   C,   generando   eseguibili   e   tutti   i   tipi   di   software   supportati   da   Mac   OS-­‐X,   compresi   strumenti   da   riga   di   comando,   frame   work,   estensioni   del   kernel,   bundle   e   applicazioni;   mentre   per   l'Iphone   sono   solo   possibili   applicazioni  eseguibili.   Essendo   specifico   per  applicazioni   Cocoa   e   in   questo   caso   usato   per   lo   sviluppo   di   un’applicazione   per   Iphone,  permette  di  scegliere  quale  tipo  di  modello  creare,  come  mostrato  nella  figura  sottostante.       2-­‐11  
  • 12.
      Figura  2:  sviluppo  di  applicazioni  Cocoa   2.2.4   Interface  Builder   La   seconda   applicazione   come   importanza   nei   progetti   Cocoa   è   l'Interface   Builder,   uno   strumento   grafico  nato  per  la  creazione  delle  interfacce  grafiche  che  è  integrato  con  Xcode,  e  che  permette  quindi   allo  stesso  programma  di  riconoscere  le  eventuali  modifiche  svolte  dal  programmatore  nel  codice  del   progetto  e  riportarle  così  nell'interfaccia  grafica.   I  quattro  principali  elementi  che  contraddistinguono  la  struttura  dell'Interface  Builder  sono:     ⇒ Nib  file   ⇒ L'inspector   ⇒ Object  library   ⇒ Connections  panel   2.2.4.1   Nib  file   Un   Nib   file   è   un   contenitore   che   include   gli   oggetti   che   compaiono   nell'interfaccia   utente   in   una   forma   di  archivio,  e  le  relative  informazioni,  comprese  la  posizione,  la  dimensione  e  i  dati  riguardanti  le  classi   personalizzate,   in   modo   da   poter   permettere   all'interface   builder   di   ricostruire   l'interfaccia   grafica   anche  dopo  la  sua  creazione.     L'Interface   Builder,   visualizzerà   il   suo   contenuto   in   una   finestra   del   documento   che   permetterà   di   accedere   agli   oggetti   del   file   come   finestre,   menù,   object   controller,   e   che   collegherà   gli   oggetti   delle   interfacce   utente   con   i   modelli   che   rappresentano   i   dati   delle   applicazioni,   fornendo   oltretutto   la   gestione  globale  dell'applicazione  da  sviluppare.     2.2.4.2    L'inspector   Include  alcuni  riquadri  selezionabili  per  impostare  la  configurazione  iniziale  di  runtime  degli  oggetti   (anche  se  le  dimensioni  e  altri  attributi  possono  essere  manipolati  direttamente).       2-­‐12  
  • 13.
    2.2.4.3    Object  Library   Contiene  gli  oggetti  che  l'interfaccia  utente  può  racchiudere,  comprendendo  sia  gli  oggetti  tipici  (come   finestre,  controlli,  menu,  text  view)  che  i  controller  di  oggetti,  viste  personalizzate  di  oggetti,  oppure   frame  work  come  ad  esempio,  l'Image  Kit.   L'Object   Library   raggruppa   oggetti   per   categorie,   facilitando   la   navigazione   e   permettendo   al   programmatore  una  più  facile  ricerca  di  elementi  grafici  specifici.     L'Interface   Builder   creerà   un'istanza   predefinita   di   un   oggetto   solo   trascinandolo   dalla   libreria   all'interfaccia,    in  modo  da  consentire  lo  sviluppatore  di  poterlo  configurare  e  collegare  ad  altri  oggetti   utilizzando  la  finestra  Inspector.   2.2.4.4   Connections  panel   Permette   di   visualizzare   le   connessioni   legate   a   un   oggetto   selezionato   nella   finestra   di   Interface   Builder,  riferita  alla  view  da  modificare.  È  possibile  quindi,  attraverso  questo  pannello,  visualizzare  e   gestire  tutte  le  connessioni  dell'oggetto  selezionato.   Qui  di  seguito  sono  riportate  le  immagini  che  descrivono  gli  elementi  sopraelencati.           Figura  3:  Da  sinistra  -­  l'Inspector,  l'Object  Library,  Connections  Panel     2-­‐13  
  • 14.
    2.2.5   Iphone  OS  simulator   La   Apple   prevedendo   l’installazione   dei   programmi   sull’Iphone   solamente   dietro   il   pagamento   di   un   abbonamento   annuale   di   99$/anno   oppure   299$/anno,   ha   previsto   nel   tool   di   sviluppo   per   i   programmatori,  anche  uno  strumento  per  il  test  dei  programmi  chiamato  Iphone  Simulator  il  cui  scopo   è  quello  di  simulare  il  funzionamento  del  vero  e  proprio  dispositivo.   Esso,   consente   allo   sviluppatore   di   poter   testare   ed   eventualmente   eseguire   il   debug   del   suo   programma   sul   computer,   prima   di   installarlo   sull’Iphone,   abilitando   l’uso   dell’interfaccia   utente   multitouch  presente  nella  realtà.   Durante  la  fase  di  test,  comunque,  lo  sviluppatore  dovrà  sempre  tenere  conto  che  la  simulazione  non   sarà   proprio   reale   al   100%   poiché   il   touch   pad   del   computer   sostituirà,   di   fatto,   il   touch   dell’Iphone   rendendo   impossibile   il   test   delle   interfacce   multitouch,   oppure   l’utilizzo   da   parte   del   simulatore   delle   librerie   Foundation   e   Core   Foundation   presenti   nel   MAC   OS   anziché   di   quelle   utilizzate   dall’Iphone   nella  realtà.   Sarà   inoltre   importante   tenere   in   considerazione   un   ultimo   elemento:   le   prestazioni   del   programma   che   sull’Iphone   simulator   saranno   notevolmente   più   veloci   poiché   il   simulatore   eseguirà   le   applicazioni  come  ospiti  del  MAC  OS  X,  quindi  sfruttando  il  processore  del  MacBook  e  la  sua  ram.       2.3 Objective-­‐C   Tale   linguaggio   è   diventato   il   più   orientato   per   lo   sviluppo   di   applicazioni   per   sistemi   Mac   OS   X   e   iPhone   OS,   nascendo   dall'esigenza   di   estendere   alla   programmazione   ad   oggetti   il   linguaggio   C.   Le   sue   caratteristiche  possono  essere  le  seguenti:     ⇒ La  struttura  è  meno  tipizzata  di  C++.     ⇒ E’  basato  sullo  scambio  di  messaggi  e  su  di  un’estrema  dinamicità.   ⇒ In  fase  di  esecuzione  fornisce  un  maggior  supporto  run-­‐time  alla  riflessione  rispetto  a  C++.   ⇒  E’  più  orientato  verso  decisioni  “dinamiche”  rispetto  al  C++.     2.3.1 Oggetti,  classi,  metodi  e  istanze   Un   programma   orientato   a   oggetti   è   generalmente   costituito   da   una   diversità   di   oggetti   che   interagiscono  tra  loro  e  che  sono  dichiarati  tramite  la  definizione  della  loro  classe.   Si   potrà   definire   un   oggetto   come   composto   principalmente   da   una   variabile   istanziata   (dato)   che   rappresenterà   lo   stato   di   un   oggetto   e   da   funzioni   che   agiranno   sulle   variabili   come   risposta   a   messaggi.   Un   oggetto   quindi   potrà   essere   visto   come   un   semplice   programma   da   chiamare   mandandogli  un  messaggio  per  eseguire  una  semplice  azione.   La   classe   invece   potrà   essere   definita   come   il   prototipo   di   un   determinato   tipo   di   oggetto,   dichiarando   le  variabili  d’istanza  che  fanno  parte  di  ogni  membro  della  classe  e  definendo  un  insieme  di  metodi  che   tutti  gli  oggetti  della  classe  possono  usare.   Il  compilatore,  quando  dovrà  produrre  gli  eseguibili  del  programma,  creerà  un  solo  oggetto  accessibile   per   ogni   classe   detto   “class   object”,   che   avrà   lo   scopo   di   generare   nuovi   oggetti   appartenenti   alla   classe.     Il   “class   object”   sarà   quindi   la   versione   compilata   della   classe,   e   gli   oggetti   che   creerà   saranno   le   istanze  della  classe  al  tempo  di  esecuzione.     2.3.2 Interfacce  e  implementazioni   L’   Objective-­‐C   richiede   che   l'interfaccia   e   l'implementazione   di   una   classe   siano   dichiarati   in   blocchi   di   codice   differenti.   Per   convenzione,   l'interfaccia   è   messa   in   un   file   con   estensione   “.h”,   mentre   l'implementazione  va  scritta  in  un  file  con  suffisso  “.m”.       2-­‐14  
  • 15.
    2.3.2.1  Interfacce   L'interfaccia  di  una  classe  è  solitamente  definita  in  un  file  “.h”.   Sfruttando  la  convenzione  di  assegnare  il  nome  del  file  basandosi  su  quello  della  classe,  un  prototipo  di   classe  potrà  essere  il  seguente:       #import "NomeDellaSuperclasse.h" @interface NomeDellaClasse : NomeDellaSuperclasse { //variabili d'istanza int variabileIntera; float variabileFloat; ... } //metodi di classe + metodoDiClasse1 + metodoDiClasse2 + ... //metodi d’istanza - metodoDiIstanza1 - metodoDiIstanza2 - ... @end   Tabella  1:  codice  esempio  dell’interfaccia  NomeDellaClasse.h   Il   segno   meno   (-­‐)   denota   i   metodi   d’istanza,   mentre   il   segno   (+)   più   quello   di   classe   (analoghi   alle   funzioni  statiche  del  C++).     2.3.2.2   Implementazioni   L'interfaccia  dichiara  solamente  i  prototipi  dei  metodi  e  non  la  loro  implementazione.  La  convenzione   è  la  medesima  dell’interfaccia.     I  metodi  sono  funzionalità  che  una  classe  può  offrire  e  ne  esistono  di  due  tipi:  quelli  ereditati  dalle   classi  da  cui  discende  e  quelli  aggiunti.   Tra   i   metodi   aggiunti   va   notato   che   sono   pubblici   tutti   quelli   richiamati   nell'interfaccia   della   classe   cui   appartengono   (file   con   estensione   .h);   sono   invece   privati   quei   metodi   implementati   direttamente   nella  descrizione  della  classe  (file  con  estensione  .m.).  Un  metodo  che  può  essere  usato  da  un’istanza   della   classe   viene   preceduto   dal   segno   “-­‐”   e   può   essere   usato   solo   in   presenza   di   una   istanza.   Un   metodo   che   invece   è   usato   indipendentemente   dalle   istanze   dalla   classe   viene   preceduto   dal   segno   “+”   e  chiamato  “metodo  di  classe”.   Una   nota   da   porre   riguarda   l'ereditarietà:   è   sempre   possibile   considerare   le   definizioni   di   classe   come   additive,  poiché  dichiarare  una  classe,  significa  aggiungere  metodi  alla  classe  da  cui  deriva.     #import "NomeDellaClasse.h" @implementation NomeDellaClasse + metodoDiClasse1 { // implementazione } + metodoDiClasse2 {   2-­‐15  
  • 16.
    // implementazione } ... - metodoDiIstanza1 { // implementazione ... } - metodoDiIstanza2 { // implementazione ... } ... @end   Codice  1:  Implementazione  della  classe  NomeDellaClasse     2.3.3 Messaggi  e  polimorfismo   In   Objective   C   è   possibile,   una   volta  creata   un'istanza   dell'oggetto,   inviargli   uno   o   più   messaggi,   con   lo   scopo  ad  esempio  di  implementare  dei  metodi  appartenenti  a  quell'oggetto.   Una   volta   che   l'oggetto   ha   svolto   il   suo   compito,   è   necessario   rilasciarlo   (attraverso   il   messaggio   release)   poiché   per   la   sua   creazione   è   stata   occupata   della   memoria   che   potrebbe   servire   per   nuovi   oggetti.   I  messaggi  scambiati  sono  dotati  di  alcune  caratteristiche  particolari:  un  oggetto  può  essere  utilizzato   soltanto   da   alcuni   metodi   che   gli   sono   associati   e   non   è   possibile   quindi   mischiare   i   metodi   tra   oggetti   anche  se  hanno  lo  stesso  nome,  permettendo  a  oggetti  diversi  di  rispondere  allo  stesso  messaggio  in   modo  differente.     Questa   caratteristica,   descritta   come   polimorfismo,   svolge   un   ruolo   rilevante   nella   progettazione   di   programmi  Objective-­‐C.   Insieme  alla  caratteristica  di  dinamicità,  in  particolare  il  binding  dinamico,  è  possibile  scrivere  codice   che   potrebbe   essere   applicato   a   un   numero   qualsiasi   di   oggetti,   senza   dover   scegliere   al   momento   dell'implementazione.   È   possibile   implementare   quindi   un   metodo   che   invia   un   messaggio   a   un   oggetto  id,  consentendo  potenzialmente  quindi  a  tutti  gli  oggetti  di  ricevere  tale  messaggio.     2.3.4   Objective-­‐C  e  oggetti  Cocoa   Cocoa  è  strutturalmente  orientato  agli  oggetti,  dai  suoi  paradigmi  e  meccanismi,  all'architettura  event-­‐ driven,  e  una  delle  sue  peculiarità  è  di  essere  improntato  allo  scambio  di  messaggi,  caratteristica  che   gli  restituisce  un  elevato  dinamismo.   Quando   un   oggetto   è   creato,   la   memoria   è   allocata   e   le   sue   variabili   d’istanza   inizializzate;   cosicché   ogni   oggetto   creato   nasconde   una   struttura   dati   il   cui   primo   membro   è   il   puntatore(isa)   che   punta   alla   classe  dell'oggetto  che  possiede,  il  quale  a  sua  volta  dispone  dei  puntatori  alle  proprie  super  classi.   Attraverso   questa   catena   di   riferimenti,   un   oggetto   ha   accesso   a   tutti   i   metodi   implementati   dalla   propria   classe   e   dalla/e   superclasse/i.   Il   puntatore   è   l’elemento   fondamentale   per   il   meccanismo   di   distribuzione   dei   messaggi   e   per   il   dinamismo   degli   oggetti   Cocoa.   Questa   visione   degli   oggetti   semplifica   notevolmente   cosa   accade   a   runtime   nell’Objective-­‐C   per   la   distribuzione   dei   messaggi,   le   gerarchie  e  altre  caratteristiche  generali  di  comportamento  degli  oggetti.       2.3.5 Dinamicità  dell’Objective-­‐C   Objective-­‐C   è   un   linguaggio   molto   dinamico,   poiché   sposta   molta   della   responsabilità   di   risoluzione   simbolica  dal  tempo  di  compilazione  al  tempo  di  runtime,  quando  il  controllo  è  dell'utente.     Esso  presenta  le  seguenti  tre  caratteristiche  di  dinamicità:     2-­‐16  
  • 17.
    ⇒ Tipizzazione  dinamica  (Dynamic  typing),  determinando  la  classe  di  un  oggetto  a  runtime   ⇒ Invocazione   dinamica(Dynamic   binding)   dei   metodi,   determinando   il   metodo   da   invocare   a   runtime   ⇒ Caricamento  dinamico(Dynamic  loading)  aggiungendo  nuovi  moduli  ad  un  software  a  runtime.     Per  la  tipizzazione  dinamica,  Objective-­‐C  introduce  il  tipo  id,  che  può  rappresentate  ogni  tipologia  di   oggetto   e   rende   possibile   la   sostituzione   di   oggetti   a   runtime,   lasciando   ad   altri   fattori   in   fase   di   esecuzione  la  scelta  di  quale  tipo  di  oggetto  inserire  nel  codice.     Tale  tipizzazione  permette  associazioni  tra  gli  oggetti  da  determinare  in  fase  di  esecuzione,  piuttosto   che  forzarli  nel  codice  in  una  struttura  statica.  I  tipi  statici  garantiscono  al  tempo  di  compilazione  una   maggiore  integrità  dei  dati,  offrendo  una  più  elevata  flessibilità.     E'   possibile   comunque   verificare   il   tipo   di   oggetto   a   runtime,   determinando   la   sua   idoneità   per   particolari  operazioni,  rendendo  comunque  anche  possibile  la  definizione  degli  oggetti  staticamente.   Il  tutto,  ha  lo  scopo  di  garantire  robustezza  all'invocazione  dinamica  di  metodi.   L’invocazione  dinamica,  rimanda  così  la  decisione  del  metodo  da  utilizzare  al  tempo  di  esecuzione.  La   chiamata  del  metodo  avviene  quindi  non  al  tempo  di  compilazione  ma  proprio  quando  un  messaggio  è   stato   recapitato.   Con   queste   due   caratteristiche   di   dinamicità   è   possibile   quindi   ottenere   diversi   risultati  ogni  volta  che  si  esegue  il  codice.     Quando   un   messaggio   è   inviato   a   un   oggetto   tipizzato   dinamicamente,   il   sistema   a   runtime   usa   il   puntatore  del  ricevitore  per  determinare  la  classe  dell'oggetto  e  da  lì  il  metodo  da  invocare,  cosicché   esso  è  legato  dinamicamente  al  messaggio.     Nel   codice,   inoltre,   non   bisogna   aggiungere   nulla   per   beneficiare   della   dinamica   dei   metodi   invocati,   perché  il  tutto  avviene  in  trasparenza  nel  momento  in  cui  è  inviato  un  messaggio,  a  maggior  ragione  se   l'oggetto  è  tipizzato  dinamicamente.   Il   caricamento   dinamico   è   la   caratteristica   di   Cocoa   che   dipende   da   Objective-­‐C   per   il   supporto   runtime.   Grazie   al   caricamento   dinamico   un   programma   Cocoa   può   caricare   codice   eseguibile   e   le   risorse  necessarie  quando  ne  ha  bisogno,  senza  doverlo  fare  al  momento  del  lancio.  Il  codice  eseguibile   (collegato   prima   del   caricamento)   spesso   contiene   nuove   classi   che   sono   integrate   nell'immagine   runtime  del  programma.  Sia  il  codice  sia  le  risorse  localizzate  (incluso  il  nib  file)  sono  contenuti  in  un   bundle  e  sono  caricate  esplicitamente  da  metodi  definiti  nella  classe  NSBundle  di  Foundation.   Questo   tipo   di   caricamento   di   codice   e   risorse   ottimizzano   le   prestazioni   diminuendo   la   memoria   richiesta  dal  sistema,  con  la  conseguenza  che  le  applicazioni  diventano  estensibili.     Altro  effetto  è  la  possibilità  di  aggiungere  un'architettura  di  plug-­‐in  alle  applicazioni,  permettendo  così   agli   sviluppatori   di   personalizzare   il   software   con   moduli   aggiuntivi   che   l'applicazione   può   caricare   molto   tempo   dopo   il   suo   rilascio,   ammettendo   però   che   il   design   sia   coerente   e   che   le   classi   non   entrino  in  conflitto.     2.3.6 Le  classi  root   Il   linguaggio   Objective-­‐C   e   il   sistema   runtime   non   sono   sufficienti   per   costruire   un   programma   orientato  a  oggetti;  manca  una  definizione  dell'interfaccia  comune  a  tutti  gli  oggetti,  ed  è  per  questo   motivo  che  deve  essere  utilizzata  la  classe  root.     Una   classe   root,   in   senso   generico   è   chiamata   così   perché   è   la   radice   di   una   gerarchia   di   classi,   non   deriva  da  nessun'altra  classe,  e  in  questo  caso  è  alla  base  della  classe  gerarchica  Cocoa.   Le  due  classi  di  tipo  root  che  sono  fornite  da  Cocoa  s’identificano  in:       ⇒ NSObject     ⇒ NSProxy     2-­‐17  
  • 18.
      Un'osservazione  importante  va  fatta  riguardo  la  classe  NSProxy  in  quanto  quest'ultima  è  definita  come   una   superclasse   astratta   per   gli   oggetti   che   agiscono   come   supporto   ad   altri   oggetti   ed   è   essenziale   nelle   architetture   di   oggetti   distribuiti.   Tale   ruolo   è   molto   specializzato   ed   è   poco   frequente   nei   programmi  Cocoa,  dove  la  maggior  parte  delle  volte  si  fa  riferimento  alla  classe  root  NSObject.   Fondamentali  sono  le  dichiarazioni  dei  metodi  per  l'assegnazione,  l'inizializzazione,  l'introspector,  la   gestione  della  memoria  e  il  supporto  al  runtime,  concetti  fondamentali  per  la  comprensione  di  Cocoa.     2.3.6.1   NSObject   NSObject  non  ha  una  super  classe:  da  essa  derivano  molte  classi  Objective-­‐C  che  ereditano  l'interfaccia   base  al  sistema  runtime  per  il  linguaggio  Objective-­‐C  e  le  sue  istanze  ottengono  le  funzionalità  tali  da   diventare  oggetti.     Anche   se   non   è   strettamente   una   classe   astratta   NSObject   lo   è   virtualmente:   infatti   un   oggetto   NSObject  non  può  fare  nulla  di  utile  al  di  là  di  essere  un  semplice  oggetto.     Per   aggiungere   gli   attributi   e   le   funzionalità   del   programma   specifico   è   necessario   creare   una   o   più   classi  ereditate  da  NSObject  o  da  qualsiasi  altra  classe  derivata:  in  pratica  NSObject  adotta  il  protocollo   NSObject  che  abilita  l'uso  di  oggetti  root.       2.3.7   Allocazione  e  rilascio  degli  oggetti   Objective-­‐C,  con  il  rilascio  di  Mac  OS  X  10.5,  ha  iniziato  ad  implementare  due  metodi  per  garantire  la   persistenza  ed  il  rilascio  di  oggetti.     L'approccio   più   utilizzato   in   Mac   OS   X   10.5   è   la   “garbage   collection”:   il   sistema   di   runtime   rileva   gli   oggetti   non   più   necessari   e   li   elimina   automaticamente,   risultando   anche   essere   la   più   semplice   da   implementare  nella  maggior  parte  dei  casi.   Il   secondo   approccio,   chiamato   “memory   management”,   si   basa   sul  conteggio   dei   riferimenti:   ciascuna   chiamata   che   rivendica   la   proprietà   di   un   oggetto   (allocazione,   inizializzazione,   copia   e   trattenuta)   deve   essere   bilanciata   da   una   chiamata   che   rimuove   tale   proprietà   (rilascio   e   autorilascio)   cosicché   ogni   oggetto   ha   un   contatore   che   indica   il   numero   di   richieste   che   riceve   e   quando   tale   contatore   decresce  fino  a  0,  l'oggetto  è  deallocato  e  la  memoria  occupata  viene  liberata.   Il   metodo   analizzato   più   attentamente,   sarà   quest'ultimo,   poiché   è   quello   implementato   nell'Iphone   OS.     2.3.7.1   Memory  management   Nel   codice   Objective-­‐C   del   memory   management   un   oggetto   Cocoa   esiste   in   più   di   un   ciclo   di   vita   e   potenzialmente  ha  diverse  fasi  di  vita  suddivise  nel  seguente  modo:     1. Allocazione  in  memoria   2. Inizializzazione   3. Uso   4. Rilascio     5. Distruzione   Oltre  a  questi  importanti  punti,  va  ricordato  che  l'oggetto  inoltre  può  essere  sia  trattenuto  che  copiato.     Per  capire  questo  ciclo  di  vita,  bisogna  innanzitutto  sapere  che  ogni  oggetto  Cocoa  ha  associato  alla  sua   esistenza   un   numero   intero,   chiamato   contatore   “retain”,   che   indica   il   numero   di   altri   oggetti   che   sono   interessati  alla  sua  persistenza.   In   seguito   all'allocazione,   l'oggetto   è   inizializzato   impostando   le   istanze   delle   sue   variabili   ad   accettabili   valori   iniziali,   attraverso   la   dichiarazione   del   metodo   init   che   è   presente   nella   classe     2-­‐18  
  • 19.
    NSObject   la   quale   lo   definisce   nel   suo   prototipo.   L'oggetto   è   così   pronto   per   essere   usato,   rendendo   possibile  quindi  l'invio  di  messaggi,  oppure  ad  esempio  il  suo  invio  ad  altri  oggetti.   Quando  si  rilascia  un  oggetto,  attraverso  un  messaggio  release,  NSObject  decrementa  il  suo  puntatore   retain  e  se  tale  valore  diventa  zero  l'oggetto  viene  deallocato  in  due  fasi.     Nella   prima   fase,   il   metodo   dealloc   dell'oggetto   è   invocato   per   rilasciare   le   istanze   delle   variabili   e   liberare   la   memoria   allocata   dinamicamente,   poi   successivamente   il   sistema   operativo   distrugge   l'oggetto   e   reclama   la   memoria   che   era   occupata   dall'oggetto   stesso:   è   importante   notare   che   non   si   dovrebbe  mai  invocare  direttamente  un  metodo  dealloc  di  un  oggetto.   Nel   caso   in   cui,   ricevuto   un   oggetto,   si   richiede   il   suo   mantenimento,   il   contatore   retain   sarà   incrementato   a   due   cosicché   saranno   quindi   necessari   due   messaggi   di   release   per   rilasciare   tale   oggetto.   In  un  programma  Objective-­‐C  è  possibile  ricevere  oggetti  da  altri  oggetti  e  inviarli  per  messaggio  ad   altri   ancora.   Queste   caratteristiche   richiedono   che   se   un   primo   oggetto   invia   un   oggetto   a   un   terzo   che   fa   da   ricevente,   il   primo   non   può   rilasciare   il   secondo   prematuramente   mentre   questo   è   utilizzato   dall'ultimo  ricevente.   Nel   caso   in   cui   il   ricevente   dell'oggetto   ha   bisogno   di   conservarlo   anche   quando   il   programma   ha   terminato  il  suo  scopo,  può  farlo,  incrementando  il  contatore  retain.     In  tal  modo  se  il  creatore  dell'oggetto  lo  rilascia,  questo  non  sarà  deallocato  e  il  ricevente  diventerà  il   responsabile  dello  stesso,  potendo  così  de  allocarlo  in  un  momento  successivo.   In  una  tale  gestione,  si  potrebbe  verificare  un  problema  nel  suo  ciclo  di  vita:   ⇒ Se  un  oggetto  ne  crea  un  altro  e  poi  lo  invia  a  un  terzo,  il  primo  potrebbe  non  sapere  quando   poterlo   rilasciare   in   sicurezza,   poiché   ci   potrebbero   essere   infatti   molteplici   riferimenti   all'oggetto   nello   stack   delle   chiamate   che   risulterebbero   essere   sconosciute   alla   creazione   dell'oggetto.     Se   l'oggetto   creatore   lo   rilasciasse   e   altri   oggetti   inviassero   un   messaggio   a   quello   distrutto,   il   programma  potrebbe  andare  in  crash.     La   soluzione   per   evitare   casi   di   questo   genere   è   stata   implementata   nel   Cocoa   introducendo   un   meccanismo  per  dilazionare  la  deallocazione  chiamata  “autorelease”.   Questa  è  un  meccanismo  che  si  avvale  dell'autorelease  pool  (definita  nella  classe  NSAutoreleasePool)   che  può  essere  spiegata  come  una  collezione  di  oggetti  all'interno  di  un  ambito  definito  esplicitamente,   contrassegnata   per   il   loro   eventuale   rilascio.   In   questa   situazione,   proprio   quando   s’invierà   un   messaggio   di   autorilascio   a   un   oggetto   si   metterà   il   riferimento   all'oggetto   nell'autorelease   pool   del   suo   ambito:   tale   oggetto   comunque   sarà   ancora   valido   cosicché   gli   altri   oggetti   che   rientreranno   nell'ambito  dell'applicazione  definito  dall'autorelease  pool  potranno  comunque  inviargli  messaggi.   Questo   metodo   è   comunque   sconsigliato   nell'Iphone   giacché   è   un   ambiente   che   ha   una   capacità   di   memoria  limitata,  soprattutto  in  metodi  o  blocchi  di  codice  in  cui  si  creano  molti  oggetti.   Si  potrà  quindi  sintetizzare  la  politica  di  proprietà  degli  oggetti  nella  seguente  maniera:   1. Nel  caso  di  allocazione  e  inizializzazione  di  un  oggetto,  si  sarà  proprietari  dello  stesso  fino  al   momento  del  suo  rilascio.   2. Se  l'oggetto  sarà  copiato,  si  sarà  comunque  responsabili  della  copia  e  del  suo  rilascio.   3. Se   si   trattiene   un   oggetto,   si   diventerà   parzialmente   proprietari   dello   stesso   e   si   dovrà   rilasciarlo  quando  non  servirà  più.   4. Al  contrario,  se  si  riceverà  da  un  altro  oggetto  un  oggetto,  non  si  diventerà  proprietari  e  non  lo   si  rilascerà.   Per   la   corretta   scrittura   di   un   programma   in   quest’ambiente,   sarà   necessario   sicuramente   seguire   queste   regole,   altrimenti   il   programma   potrebbe   richiedere   troppa   memoria   al   dispositivo   e   mandarlo     2-­‐19  
  • 20.
    in   crash,   come   nel   caso   in   cui   ci   sia   l'invio   di   un   messaggio   a   un   oggetto   deallocato   in   maniera   non   controllata.   Queste  situazioni  in  linea  di  massima  dovrebbero  essere  evitate  attraverso  una  procedura  dettagliata   di  debug  del  programma.   2.3.7.1.1   Allocazione   L'allocazione   permette   di   destinare   a   un   oggetto   Cocoa   una   porzione   di   memoria   virtuale   del   dispositivo  associata  al  programma.     Per  valutarne  la  sua  entità  si  prendono  in  considerazione  le  variabili  d’istanza  dell'oggetto,  inclusi  i  tipi   ed  il  loro  ordine,  come  specificato  dalla  classe  dell'oggetto.     Quest’operazione   avviene   attraverso   l'invio   del   messaggio   “alloc”:   alla   classe   dell'oggetto   sarà   restituita   un'istanza   grezza,   ovvero   non   inizializzata   di   quella   classe,   con   l'utilizzo   della   memoria   interna  destinata  al  programma.     Oltre  a  quest’operazione,  si:     ⇒ Configurerà  il  contatore  retain  a  1.   ⇒ S’inizializzerà  il  puntatore  all'oggetto  indicandogli  la  classe  dell'oggetto  stesso.   ⇒ S’inizializzerà  a  zero  o  a  valori  “nil”  tutte  le  variabili  della  classe.     Essendo   il   puntatore   dell'oggetto   (chiamato   anche   “isa”)   ereditato   da   NSObject,   è   comune   a   tutti   gli   oggetti   Cocoa;   viene   configurato   alla   classe   dell’oggetto   da   inizializzare,   solo   dopo   aver   allocato   la   memoria  da  lasciare  all’oggetto  stesso.  E’  integrato  nella  vista  runtime  della  gerarchia  dell'ereditarietà   delle  classi  e  nella  rete  di  oggetti  che  costituiscono  il  programma.   Tutto   questo   procedimento   porterà   all’agevolazione   della   ricerca   delle   informazioni   al   tempo   d’esecuzione  del  programma.   Si  può  dire  che  l'allocazione  di  un  oggetto  in  memoria  consta  oltre  alla  predestinazione  di  una  parte   della  memoria  stessa  alla  variabile,  anche  di  due  inizializzazioni  riguardanti  il  contatore  “retain”  e  la   variabile  di  tipo  puntatore  “isa”,  non  rendendo  ancora  di  fatto  usabile  l'oggetto.     2.3.7.1.2    Inizializzazione   Quest’operazione  ha  come  scopo  quello  di  impostare  le  variabili  d’istanza  di  un  oggetto  a  valori  iniziali   coerenti   con   le   variabili   stesse,   potendo   inoltre   allocare   e   disporre   altre   risorse   globali   di   cui   l'oggetto   deve   disporre   durante   il   suo   funzionamento.   Una   particolare   osservazione   va   fatta   a   riguardo   di   quest’operazione,   ossia   che   ogni   oggetto   presente   nel   programma,   dovrebbe   essere   inizializzato   tramite   un   suo   metodo   d’inizializzazione,   purché   non   sia   soltanto   necessaria   l'inizializzazione   di   default.  Nel  caso  in  cui,  non  si  preveda  un'inizializzazione  “personalizzata”  per  un  determinato  oggetto   e   Cocoa   lo   andrà   a   inizializzare   con   il   metodo   d’inizializzazione   più   vicino   gerarchicamente   all'oggetto   stesso.     2.3.7.1.3   Dealloc   Nelle  classi  Cocoa  che  usano  una  gestione  tradizionale  della  memoria,  il  metodo  usato  per  liberare  le   risorse   è   il   “dealloc”:   da   molti   punti   di   vista   questo   metodo   può   essere   considerato   come   la   controparte  del  metodo  init  della  classe.   Esso   è   invocato   proprio   prima   della   distruzione   dell'oggetto,   garantendo   che   le   istanze   dell'oggetto   vengano  rilasciate  e  che  la  memoria  allocata  dinamicamente  venga  liberata.   I   metodi   init   e   dealloc   possono   essere,   di   fatto,   considerati   complementari   in   quanto,   il   primo   invoca   il   designato  della  super  classe  al  primo  passo,  mentre  dealloc  invoca  il  suo  omologo  della  super  classe   solo  alla  fine.     2-­‐20  
  • 21.
    2.3.8   Introspection   E'   una   caratteristica   molto   potente   degli   ambienti   e   linguaggi   orientati   a   oggetti;   in   pratica   ci   si   riferisce  alla  capacità  di  un  oggetto  di  divulgare  le  sue  informazioni  nella  fase  di  runtime.     Tali   dettagli   riguardano   il   posto   nella   catena   gerarchica,   la   conformità   a   determinati   protocolli   e   le   risposte   a   determinati   messaggi.   Il   protocollo   e   la   classe   NSObject   definiscono   molti   metodi   introspection  che  si  possono  usare  a  runtime  per  caratterizzare  gli  oggetti,  permettendo  di  acquisire   familiarità  con  la  classe  dell’oggetto  e  di  conoscere  ad  esempio  quali  messaggi  inviare  oppure  non  a  un   determinato  oggetto.   Il   protocollo   NSObject   fornisce   diversi   metodi   per   determinare   la   posizione   di   un   oggetto   nella   gerarchia  delle  classi  operando  su  diversi  livelli  di  granularità.     I  metodi  d’istanza  delle  classi  e  superclassi  per  esempio,  restituiscono  oggetti  Class  che  rappresentano   rispettivamente   la   classe   e   la   superclasse   per   il   ricevitore:   essi   richiedono   di   confrontare   un   oggetto   Class  con  un  altro  o  per  ottenere  un  ricevitore  appropriato  da  una  classe  di  messaggi.   I   messaggi   invece   isKindOfClass:   oppure   isMemberOfClass:   permettono   di   verificare   la   classe   di   appartenenza  di  un  oggetto  portando  ai  seguenti  risultati:     • Il  primo  restituisce  una  conferma  o  meno  se  il  ricevitore  è  un'istanza  di  una  determinata  classe   o  di  una  classe  da  essa  derivata.     • Un  messaggio  isMemberOfClass:  d'altro  canto,  restituisce  conferma  se  il  ricevitore  è  un'istanza   di  una  specifica  classe.     Il  messaggio  più  usato  è  il  “isKindOfClass”  poiché  da  esso  è  possibile  ricavare  in  un  solo  passaggio  la   gamma  completa  di  messaggi  da  poter  inviare  a  un  oggetto.     if ([item isKindOfClass:[NSData class]]) { const unsigned char *bytes = [item bytes]; unsigned int length = [item length]; // ...}   Tabella  2:  Esempio  di  codice  con  isKindOfClass   Sapendo  che  l'oggetto  item  deriva  dalla  classe  NSData,  il  codice  successivo  sa  di  poter  inviare  lenght   byte  e  il  messaggio  NSData.     La   differenza   tra   isKindOfClass:   e   isMemberOfClass:   diventa   evidente   se   si   assume   che   item   è   un'istanza  di  NSMutableData.   Se  si  usa  isMemberOfClass:  al  posto  diisKindOfClass:,  il  codice  nel  blocco  non  sarà  mai  eseguito  perché   item  non  è  un'istanza  di  NSData  ma  di  NSMutableData,  una  sua  sottoclasse.     2.3.9   Oggetti  modificabili   Gli  oggetti  Cocoa  possono  essere  raggruppati  in  due  insiemi  secondo  la  loro  modificabilità:     ⇒ mutabili   ⇒ immutabili     I   due   si   differenziano   perché   nell'insieme   dei   “mutabili”   gli   oggetti   quando   sono  creati   possono   subire   delle  modifiche  nel  loro  valore,  mentre  nei  secondi,  essi  dopo  l'inizializzazione  rimangono  gli  stessi.   Le  impostazioni  predefinite  degli  oggetti  prevedono  che  essi  siano  mutabili.   Il  frame  work  Foundation,  aggiunge  altre  caratteristiche  introducendo  il  concetto  di  classi  che  hanno   varianti  mutabili  e  non,  come  nel  caso  delle  classi  NSMutableArray,  NSMutableString,  etc...   La   necessità   di   rendere   un   oggetto   immutabile   risiede   nel   fatto   che   alcune   volte,   trattando   oggetti   mutabili   ci   potrebbero   essere   problemi   di   coerenza   dei   dati,   poiché   una   variabile   potrebbe   inaspettatamente  cambiare  valore  mentre  è  usata,  oppure  per  un  incremento  delle  prestazioni  poiché     2-­‐21  
  • 22.
    se   un   oggetto   è   mutabile,   avrà   anche   dei   controlli   nella   gestione   della   quantità   di   memoria   da   allocare   e  deallocare  che  rallenteranno  il  programma.   La  politica  da  adottare  sulla  scelta  se  implementare  o  no,  variabili  mutabili,  è  esplicata  qui  di  seguito,   in  maniera  molto  sintetica:     • Utilizzare  varianti  mutabili  di  oggetti  quando  richiedono  frequenti  modifiche.     • E’  consigliabile  sostituire  un  oggetto  immutabile  piuttosto  che  gestirne  uno  mutabile  se  questo   non  richiede  modifiche  frequenti.     2.3.10   Raggruppamenti  di  classi   Il   raggruppamento   di   classi   (detta   anche   Class   cluster)   è   uno   strumento   che   estende   l'uso   del   frame   work  Foundation.     Lo  scopo  che  persegue  è  di  raggruppare  un  certo  numero  di  sottoclassi,  private  e  concrete  sotto  una   super  classe  pubblica  e  astratta  con  lo  scopo  di  semplificare  l'architettura  pubblica  visibile  di  un  frame   work  orientato  agli  oggetti  senza  ridurne  le  potenzialità.   La   super   classe   astratta   deve   dichiarare   metodi   per   creare   istanze   delle   sue   sottoclassi   private,   ed   inoltre,  è  responsabilità  della  super  classe  dispensare  un  oggetto  della  propria  sottoclasse  basato  su  un   metodo  invocato.  Non  è  possibile  e  non  si  deve,  scegliere  la  classe  dell'istanza.   È   anche   spesso   utile,   avere   due   o   più   classi   astratte   pubbliche   che   dichiarino   l'interfaccia   del   raggruppamento.     Questo  è  evidente  nel  Framework  Foundation  che  include  questi  raggruppamenti:   • NSData  diviso  in  NSData  e  NSMutableData;   • NSArray  diviso  in  NSArray  e  NSMutableArray;   • NSString  diviso  in  NSArray  ed  NSMutableString;   • NSDictionary  diviso  in  NSDictionary  e  NSMutableDictionary.   3 PROGETTAZIONE     In   questo   capitolo   è   analizzata   la   progettazione   di   tutto   il   sistema:   il   lavoro   per   essere   sviluppato   in   maniera   più   semplice   è   stato   suddiviso   in   più   moduli,   ciascuno   dei   quali   focalizza   le   singole   problematiche  e  cerca  di  risolverle  in  maniera  da  agevolare  lo  sviluppo  del  lavoro  complessivo  come   raffigurato  nel  seguente  grafico:         3-­‐22  
  • 23.
    Dexinizione  dell'obiettivo   Analisi  dei  problemi  generici   (implementazione  dei  sensori  e  delle   periferiche  del  dispositivo  nel  progetto)   Analisi  delle  singole  problematiche   Implementazione  del  prodotto  xinale     3.1 Definizione  dell’obiettivo   Il   programma   che   ha   come   oggetto   la   tesi   è   la   creazione   di   un   sistema   implementato   su   Iphone   che   riesca  tramite  l'obiettivo  della  macchina  fotografica  a  riconoscere  dei  POI  (punti  d’interesse)  inseriti   dall'utente  nella  memoria  del  dispositivo  oppure  scaricati  da  web,  localizzati  nelle  sue  vicinanze,  che  li   visualizzi  su  una  mappa  e  che  infine  fornisca  all’utente  le  funzioni  semplificate  di  un  navigatore.     3.2 Analisi  dei  problemi  generici     Prima  dello  sviluppo  del  codice  necessario  al  programma,  si  è  dovuto  attuare  uno  studio  generico  sui   sensori   e   periferiche   già   integrati   sull'Iphone   decidendo   quindi   il   modello   sul   quale   avviare   la   progettazione,   in   modo   da   essere   compatibili   con   l'obiettivo   iniziale;   poiché   non   tutte   le   versioni   presenti  sul  mercato  in  questo  momento  hanno  le  periferiche  integrate  richieste.   Una   volta   imposto   il   modello,   si   sono   analizzati   i   problemi   riguardanti   la   gestione   e   l'implementazione   delle  librerie  nel  progetto  con  la  documentazione  presente  sul  sito  internet  della  Apple,  con  lo  scopo  di   apprendere  le  nozioni  riguardanti  il  funzionamento  teorico  e  pratico  delle  librerie  per  la  gestione  del   ricevitore  GPS,  della  foto  camera,  dell’accelerometro  e  del  magnetometro,  quest’ultimo  presente  solo     nella  versione  dell’Iphone  3GS.     3.3 Scomposizione  delle  singole  problematiche   I  problemi  iniziali  su  cui  si  è  posta  maggiore  attenzione  sono  stati  i  seguenti:   ⇒ La  gestione  della  macchina  fotografica  integrata  e  della  memorizzazione  di  eventuali  foto   scattate  dall'utente.   ⇒ La  gestione  del  ricevitore  GPS,  del  magnetometro  e  dell’accelerometro.     ⇒ L'associazione  di  informazioni  aggiuntive  alle  foto  scattate  come  ad  esempio  la  latitudine,  la   longitudine  ed  un  campo  descrittivo  di  ogni  singolo  scatto.   ⇒ La  visualizzazione  degli  eventuali  punti  d’interesse  memorizzati,  sull'obiettivo  della  fotocamera.     3-­‐23  
  • 24.
    ⇒ L'eventuale  iterazione  del  dispositivo  con  un  web  service  per  permettere  all'utente  di   visualizzare  a  suo  piacimento  i  POI  (punti  d’interesse)  posti  attorno  alla  sua  posizione.   ⇒ La  localizzazione  sulla  mappa  dei  punti  d’interesse.   ⇒ La  memorizzazione  dei  dati.   ⇒ L’uso  dei  dati  provenienti  da  un  web-­service.   ⇒ Il  frame  work  MapKit.   ⇒ La  libreria  dell’Augmented  Reality(AR).       Figura  4:  Progetto  finale     3.3.1 Gestione  del  frame  work  CoreLocation   La  classe  principale  del  CoreLocation  è  la  CLLocationManager  che  rappresenta  l’entry  point  per  tutte  le   applicazioni   che   vogliono   interagire   con   il   ricevitore   GPS   per   ottenere   la   sua   posizione   corrente   in   coordinate  espresse  in  latitudine  e  longitudine.   I  passi  da  seguire  per  ricavare  queste  informazioni  sono  i  seguenti:   ⇒ La  creazione  di  un'istanza  della  classe  CLLocationManager  se  non  esiste  già;   ⇒ La  sua  configurazione  attraverso  il  settaggio  dei  suoi  parametri.   ⇒ L’invocazione  del  metodo  startUpdatingLocation  per  iniziare  la  localizzazione  dell’utente.   ⇒ L’invocazione  dello  stopUpdatingLocation  per  lo  stop  della  localizzazione.     Nel  secondo  passaggio  i  parametri  da  impostare  saranno  i  seguenti:   1. desideredAccuracy.:   imposta   una   determinata   precisione   nella   misurazione(in   termini   di   metri).     Per  questa  configurazione  posso  ricorrere  ai  seguenti  parametri:   o kCLLocationAccuracyBest.  Specifica  la  migliore  precisione  di  default.     o kCLLocationAccuracyNearestTenMeters.  Impone  una  precisione  di  10  metri.   o kCLLocationAccuracyHundredMeter.  Impone  una  precisione  di  100  metri.   o kCLLocationAccuracyKilometer.  Accuratezza  di  1000  metri.     3-­‐24  
  • 25.
    o kCLLocationAccuracyThreeKilometers.  Rappresenta   una   precisione   di   3000   metri.   2. distanceFilter.:il   valore   di   questa   proprietà   determina   quanto   spesso   viene   eseguito   un   aggiornamento   sul   posizionamento,   in   termini   di   distanza   percorsa   dall'utente.   Tutti   i   valori   qui  riferiti  sono  espressi  in  metri.     3. delegate.:questa   proprietà   specifica   il   delegate   che   riceve   gli   aggiornamenti   ovvero   la   classe   scritta   dallo   sviluppatore   che   implementa   il   protocollo   CLLocationManagerDelegate.   Esso   è   dotato  di  due  metodi  non  obbligatori:   o locationManager:didUpdateToLocation:fromLocation:.   o locationManager:didFailWithError:.     Il   primo   è   un   metodo   invocato   quando   il   location   manager   vuole   aggiornare   la   posizione  del  dispositivo.     Riceve  come  primo  riferimento,  un  riferimento  al  location  manager,  mentre  il  secondo   parametro  è  un'istanza  della  classe  CLLocation  che  ingloba  la  nuova  posizione.   Il   secondo   metodo   invece   è   invocato   solo   in   caso   di   errore   (ad   esempio   quando   non   sia   attivo  il  ricevitore  GPS  integrato).     Non   bisogna   inoltre   dimenticare   di   implementare   all'interno   del   codice   il   protocollo   CLLocationManagerDelegate   e   assegnare   l'istanza   di   questa   classe   alla   proprietà   delegate  dell'istanza  del  CLLocationManager.     3.3.1.1 La  classe  CLLocation   La  latitudine  e  la  longitudine  sono  dei  dati  espressi  in  gradi  che  definiscono  una  “griglia”  virtuale  per  il   globo   terrestre   con   lo   scopo   di   creare   un   sistema   di   riferimento   per   l'individuazione   di   un   generico   punto  sulla  Terra.     Il   sistema   di   rilevamento   adottato   è   il   GPS   che   utilizza   come   coordinate   di   riferimento   l'ellissoide   WGS84  e  avrà  per  la  latitudine  un  intervallo  che  andrà  da  -­‐90°  a  +90°,  rispettivamente  per  il  Polo  Sud  e   il  Polo  Nord,  mentre  in  longitudine  si  avrà  un  intervallo  compreso  tra  -­‐180°  e  +180°.   La   classe   CLLocation   incapsulerà   i   dati   della   posizione   generica   di   un   utente,   generati   da   un   oggetto   CLLocationManager  e  li  memorizzerà  all'interno  delle  seguenti  proprietà:     ⇒ coordinate:  conterrà  la  latitudine  e  la  longitudine  del  dispositivo  in  gradi.     ⇒ altitude.:   restituisce   l'altezza   del   dispositivo   in   metri.   I   valori   positivi   indicano   l'altezza   sopra   il   livello  del  mare  mentre  quelli  negativi  indicano  un'altezza  sotto  il  livello  del  mare.   ⇒ horizontalAccuracy   &   verticalAccuracy.:   entrambe   restituiscono   delle   precisioni   delle   misure   effettuate  riguardo,  la  prima  le  coordinate  piane  mentre  la  seconda  l’altezza.   ⇒ timestamp.:  corrisponde  all'epoca  in  termini  temporali  di  quando  è  stata  eseguita  la  misura.     Nella   maggior   parte   dei   casi,   gli   oggetti   di   tipo   CLLocation   sono   ricevuti   dal   location   manager,   ma   si   potrebbe  comunque  inizializzare  in  maniera  indipendente  quest'oggetto  con  i  seguenti  due  metodi:   ⇒ initWithLatitude:longitude:   ⇒ initWithCoordinate:altitude:horizontalAccuracy:  verticalAccuracy:timestamp:.     Esiste   un   ultimo   metodo,   presente   nella   classe,   che   è   utilizzato   per   calcolare   la   distanza   percorsa   dall'utente  ed  è  chiamato  getDistanceFrom:.     @property (nonatomic, retain) CLLocationManager *locationManager; @property (nonatomic, retain) CLLocation *newCenter;   - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation   3-­‐25  
  • 26.
    fromLocation:(CLLocation *)oldLocation { newCenter = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude]; }   Codice  2:  implementazione  della  classe  CLLocation   3.3.1.2 La  classe  CLHeading     La   versione   più   recente   del   dispositivo   (l'Iphone   3GS)   dispone   di   un   magnetometro   che   permette   di   restituire  i  valori  del  Nord  magnetico  del  campo  terrestre,  espressi  attraverso  gradi  centesimali  .   Essa   è   sempre   gestita,   come   nel   caso   del   GPS,   dal   frame   work   CoreLocation   e   in   particolare   dal   CLLocationManager.   Le   chiamate   dedicate   alla   gestione   del   magnetometro   restituiscono   oggetti   di   tipo   CLHeading   che   avranno  le  seguenti  proprietà:     ⇒ magneticHeading     ⇒ trueHeading     ⇒ headingAccuracy   ⇒ timestamp     La  prima  restituirà  il  polo  nord  magnetico  che  corrisponderà  al  campo  magnetico  della  Terra,  mentre   la   seconda   conterrà   il   valore   corrispondente   al   polo   geografico.   La   terza   proprietà   conterrà   la   precisione  della  misura  e  la  quarta  invece  il  periodo  in  cui  è  stata  compiuta  la  misura.   @property (nonatomic, retain) CLLocationManager *locationManager; … self.locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; … - (void)locationManager:(CLLocationManager *)manager didUpdateHeading: (CLHeading *)newHeading { // rotazione in radianti float rotation = newHeading.trueHeading * M_PI / 180; ... }   Codice  3:  implementazione  della  classe  CLHeading     3-­‐26  
  • 27.
    3.3.2 Gestione  dell’UIAccelerometer       Figura  5:  Assi  corrispondenti  all'accelerometro   E'  necessario  come  prima  cosa,  considerare  l'accelerometro  installato  all'interno  del  dispositivo  come   un  aiuto  per  la  costruzione  delle  interfacce  grafiche  poiché  grazie  a  questo  elemento,  l'utente  riesce  a   visualizzare   in   maniera   corretta   l'interfaccia   grafica   adattandola   alle   condizioni   fisiche   esterne   come   ad   esempio   nel   caso   della   rotazione   dell'Iphone.   Implementando   al   suo   interno   le   funzioni   dell'accelerometro  si  potrà  far  ruotare  la  schermata  nel  senso  d’inclinazione  dello  schermo.     (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrienta tion { // Return YES for supported orientations return (interfaceOrientation == UIInterfaceOrientationPortrait); }     Questa   funzione   che   permette   di   ottenere   questo   risultato   è   implementata   nella   forma   standard   del   codice,  cosicché  il  programmatore  non  sarà  obbligato  a  implementarla  autonomamente  durante  ogni   creazione  delle  interfacce  grafiche.   Qualora   però   si   volessero   utilizzare   i   dati   dell’accelerometro   nel   progetto,   si   dovrà   aggiungere   all’header   del   suo   UIViewController,   il   protocollo   UIAccelerometerDelegate   dichiarando   poi   nello   sviluppo   della   classe,   il   metodo   accelerometer:didAccelerate     che   ritornerà   i   dati   riguardanti   lo   spostamento  sugli  assi(x,y,z)  espressi  in  valori  di  tipo  floating  point.         @interface AccelController : UIViewController <UIAccelerometerDelegate> { UIAccelerometer *accelerometer; }   … accelerometer = [UIAccelerometer sharedAccelerometer]; accelerometer.updateInterval = 0.1; accelerometer.delegate =   3-­‐27  
  • 28.
    … (void)accelerometer:(UIAccelerometer *)meter didAccelerate:(UIAcceleration *)acceleration{ float x = acceleration.x; float y = acceleration.y; float z = acceleration.z; float angle = atan2(y, x); self;   Codice  4:  Implementazione  dell’UIAccelerometer   3.3.3 Gestione  della  fotocamera   La   gestione   diretta   dell’obiettivo   integrato   nell’Iphone   e   della   sua   libreria   fotografica,   è   delegata   al   controller  UIImagePickerController,  che  abilita  la  selezione  e  la  modifica  di  una  generica  foto.   Lo  sviluppatore,  per  poterlo  utilizzare,  determina  prima  il  tipo  di  sorgente  da  adoperare  e  poi  il  suo   delegate,   ovvero   la   classe   che   risponde   a   tutti   i   singoli   eventi   scatenati   dall'utente   quando   usa   la   fotocamera  del  telefono.   La  persona  che  sviluppa  programmi  in  Objective-­‐C  deve  tenere  in  considerazione  che  nel  simulatore   usato  per  testare  il  programma,  come  anche  in  altri  dispositivi  Apple  presenti  sul  mercato  (ad  esempio   l'Itouch),   la   fotocamera   non   è   implementata,   quindi   dovrà   ricorrere   ad   una   verifica   preventiva   sulla   sua  presenza  attraverso  la  seguente  funzione:       +  (BOOL)isSourceTypeAvailable:(UIImagePickerControllerSourceType)  sourceType     Essa   ritornerà   un   valore   booleano   corrispondente   al   “YES”   se   la   camera   sarà   nel   dispositivo   oppure   “NO”  nel  caso  sia  assente.   I  tipi  di  sorgente  validi  saranno  tre:   I. UIImagePickerControllerSourceTypePhotoLibrary:per   la   selezione   delle   foto   dalla   libreria  dell'Iphone;   II. UIImagePickerControllerSourceTypeCamera:  per  la  selezione  delle  foto  dalla  camera;   III. UIImagePickerControllerSourceTypeSavedPhotoAlbum:  per  la  selezione  delle  immagini   dal  rullino  della  camera  o  dalla  libreria  se  il  dispositivo  non  è  provvisto  della  camera.     Le  proprietà  dell’UIImagePickerController  da  impostare  saranno  due:   ⇒ delegate   ⇒ sourceType   Il   delegate   è   stato   descritto   precedentemente,   mentre   per   quanto   riguarda   la   seconda   proprietà,   verrà   configurata  utilizzando  uno  dei  tre  tipi  di  sorgente  appena  menzionati.    La   classe   che   sarà   delegata   dal   controller   (potrà   essere   essa   stessa   il   suo   delegate),   dovrà   essere   sviluppata   seguendo   il   protocollo   UIImagePickerControllerDelegate   che   prevederà   l’implementazione   di  due  metodi:   ⇒ -­(void)imagePickerController:(UIImagePickerController*)picker   didFinishPickingMediaWithInfo:(NSDictionary  *)info    richiamato  quando  un  utente  selezionerà   una  foto  dalla  camera  o  un'immagine  dalla  libreria  fotografica;   ⇒  -­(void)imagePickerControllerDidCancel:(UIImagePickerController   *)picker   richiamato   quando   l'utente  invece  annullerà  la  selezione;       3-­‐28  
  • 29.
    Il   primo   metodo   ha   come   parametri   in   ingresso   un   riferimento   all’image   picker   mentre   il   secondo   parametro  sarà  di  tipo  dictionary  poiché  conterrà  le  informazioni  riguardanti  l’editing  della  foto.   3.3.4 La  memorizzazione  dei  dati   Il  sistema  scelto  nel  progetto  per  la  memorizzazione  dei  dati  in  maniera  persistente  è  stato  quello  del   CoreData.   Figura  6:  Struttura  del  CoreData   Esso   è   un   sistema,   il   cui   rilascio   è   avvenuto   in   parallelo   alla   disponibilità   al   pubblico   del   sistema   operativo   Iphone   OS   X   3.0   SDK.   Poiché   fin   da   subito   si   è   dimostrato,   essere   più   veloce,   robusto   e   intuitivo   per   la   programmazione   rispetto   al   sistema   di   tabelle   SQLite   disponibili   nelle   versioni   precedenti  del  sistema  operativo,  ha  avuto  una  rapida  diffusione  nell’implementazione  nei  programmi.   I  vantaggi  riguardano  l’introduzione  di  un  sistema  per  la  visualizzazione   dei  modelli  dati  e  la  presenza   di   un’infrastruttura   per   il   controllo   degli   oggetti   con   la   conseguente   separazione   della   gestione   dell’oggetto  da  parte  del  codice.   Questo  frame  work  consiste  di  tre  parti  importanti:   ⇒ managed  object  model  che  contiene  una  collezione  di  oggetti  e  delle  loro  relazioni   ⇒ managed  object  context  contiene  gli  oggetti  creati  dalle  entità   ⇒ data  store  raggruppa  tutti  gli  oggetti  creati  attraverso  il  managed  object  model.     3.3.4.1 Il  modello   Il  concetto  fondamentale  da  ricordare  è  che  un  modello  è  considerato  come  un  contenitore  delle  entità,   e  le  entità  contengono  gli  attributi:  in  Xcode  esso  è  riconosciuto  nel  file  con  estensione  xcdatamodel  e   tramite  il  corretto  editor  sarà  possibile  inserirvi  le  tabelle  e  stabilire  le  relazioni  tra  le  varie  entità.   3.3.4.2 Le  entità   Le   entità   nei   modelli   forniscono   per   le   librerie   “Core   Data   “   il   come”   istanziare   nuovi   oggetti   e   memorizzarli.   Esse   sono   rappresentate   tramite   la   classe   NSEntityDescription   e   descritte   tramite   le   istanze   di   NSManagedObject  che  in  questo  sistema  rappresentano  i  dati  persistenti.     3.3.4.3 Managed  object  model   L'NSManagedObjectModel   contiene   le   entità   e   le   sue   relazioni   fungendo   da   schema   dell'applicazione   attraverso  la  descrizione  delle  entità  usate  nel  “managed  object  context”.     3-­‐29  
  • 30.
    La   via   più   semplice   per   ottenerlo   è   mediante   il   metodo   mergedModelFromBundles   che   crea   il   managedObjectModel   attraverso   la   fusione   di   tutti   i   modelli,   come   mostrato   nel   seguente   pezzo   di   codice:   managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles: nil] retain];     3.3.4.4 Managed  object  context   Questa   classe   rappresenta   il   “contesto”   dell’applicazione   ovvero   il   punto   dove   vengono   aggiunte   le   entità  all’applicazione.  Per  poterlo  ottenere  all’interno  di  un’applicazione,  si  dovrà:   ⇒ Allocare  e  inizializzare  una  nuova  istanza  della  classe  ManagedObjectContext   ⇒ Impostare  il  PersistentStoreCoordinator   managedObjectContext = [[NSManagedObjectContext alloc] init]; [managedObjectContext setPersistentStoreCoordinator: coordinator];     3.3.4.4.1 NSManagedObject   Analizzando   meglio   il   funzionamento   si   potrà   dire   che   l'NSManagedObjectContext   gestisce   le   istanze   della  classe  NSManagedObject  che  sono  create  dalle  entità.   L'applicazione   preleverà   i   dati   dal   persistent   store   usando   le   entità   nel   modello   per   creare   l'NSManagedObject   situato   nel   contesto:   le   NSEntityDescription   saranno   considerate   come   classi   e   l'NSManagedObject  come  oggetti.     3.3.4.4.2 Fetching  entities   I  managed  object  rimangono  nel  persistent  data  store  fino  a  quando  sono  necessari:  gli  oggetti  richiesti   al  persist  data  store  sono  memorizzati  usando  la  classe  NSFetchRequest  che  ingloba  il  criterio  di   ricerca  per  la  restituzione  di  determinati  dati  dal  persistent  data  store.   Una  richiesta  di  questo  tipo  sarà  composta  di  un  NSEntityDescriptor  e  di  due  elementi  non  obbligatori:     ⇒ NSPredicate   ⇒ NSSortDescriptor     3.3.4.4.2.1 NSPredicate   Questa   classe   pone   delle   restrizioni   nei   dati   restituiti   dall’NSFetchRequest:   potrebbe   essere   paragonata  al  WHERE  nell'SQL.   3.3.4.4.2.2 NSSortDescriptor   Questa   classe   permetterà   di   restituire   una   collezione   di   dati   provenienti   dal   CoreData   secondo   un   certo  criterio.     NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"namePhoto" ascending:NO]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; [fetchRequest setSortDescriptors:sortDescriptors];     3.3.4.4.3 NSFetchRequest   E'   la   classe   utilizzata   per   eseguire   le   interrogazioni   al   sistema   di   tabelle   assieme   alla   NSEntityDescription  che  è  usato  per  conoscere  quale  entità  si  analizza.     3-­‐30  
  • 31.
    Per  poterla  usare,  è  necessario  prima,  creare  due  istanze,  una  della  classe  NSEntityDescription  e  l’altra   della  NSFecthRequest,  poi  è  necessario  associare  la  NSEntityDescription  alla  NSFetchRequest  ed  infine   ci  sarà  la  NSManagedRequest    che  eseguirà  la  richiesta.     // Create the fetch request for the entity. NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; // Edit the entity name as appropriate. NSEntityDescription *entity = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:managedObjectContext]; [fetchRequest setEntity:entity];   3.3.4.4.4 deleteObject   Come   dice   il   nome   stesso   del   metodo,   si   trova   nella   classe   NSManagedObjectContext   e   serve   per   la   cancellazione  degli  oggetti  dal  managed  Object  context    dall’applicazione.   NSManagedObjectContext *context = [fetchedResultsController managedObjectContext]; [context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];     3.3.4.4.5 insertNewObjectForEntityForName   Tutti  gli  oggetti  gestiti  da  un  managed  object  context  sono  istanze  della  classe  NSManagedObject  che   è     una  classe  che  implementa  il  “comportamento”  richiesto  per  un  modello  CoreData.   Non  è  possibile  creare  istanze  di  NSManagedObject,  ma  solo  sottoclassi,  create  solitamente  dalle  entità   (tabelle)  definite  nel  file  xcdatamodel.   Il  codice  quindi  compirà  le  seguenti  azioni:   1. Creare  un  nuovo  ManagedObjectContext  basato  sull'entità;   2. Inserire  il  managed  object  context  corrente.   PhotoPoint *image = [NSEntityDescription insertNewObjectForEntityForName:@"PhotoPoint"inManagedObjectContext:photo.managed ObjectContext]; photo.photoPoint = image; [image setValue:selectedImage forKey:@"photoPoint"];     Dopo  l'inserimento  sarà  possibile  eseguire  le  impostazioni  alle  sue  proprietà.   3.3.4.5 NSPersistentStore   Questa  classe  ha  il  compito  di  gestire  uno  o  più  sistemi  di  memorizzazione  (tabelle)  associati  al  loro   managed  object  model,  o  a  più  “persistent  store”.   I  tipi  di  memorizzazione  per  la  persistenza  dei  dati  si  suddividono  in:   ⇒ NSSQLiteStoreType   ⇒ NSBinaryStoreType   ⇒ NSInMemoryStoreType   Nel  seguente  esempio  di  codice  è  mostrata  la  procedura  di  assegnazione  del  persistent  store  :   1. Definizione  della  memorizzazione  con  il  caricamento  del  database  SQLite  dalla  cartella   Document  dell'applicazione.     3-­‐31  
  • 32.
    2. Creazione  dell'URL  dal  database  e  dell'istanza  del  NSPersistentStoreCoordinator   3. Inizializzazione  da  parte  del  coordinator  dello  store  coordinator  usando  un'istanza  del   managed  object  model       NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"photo.sqlite"]];//CompactNavigator.sqlite NSError *error = nil; persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];     3.3.5 Uso  dei  dati  provenienti  da  un  web  service   Una  delle  caratteristiche  richieste  maggiormente  per  quanto  concerne  lo  sviluppo  di  applicazioni  per   dispositivi  mobili  è  la  possibilità  di  interagire  e  scambiare  informazioni  tramite  web,  ad  esempio  per   mezzo   dell'iterazione   con   i   web   services   ovvero   servizi   web   resi   disponibili   gratuitamente   e   non,   da   server  e  aziende  in  località  remote  rispetto  al  dispositivo  mobile.   Solitamente,  gli  ambienti  di  sviluppo  più  recenti  sono  predisposti  già  per  la  creazione  di  applicativi  di   questo   tipo:   Xcode   che   è   il   tool   usato   per   le   applicazioni   su   Iphone,   non   dispone   di   un   ambiente   intrinseco   per   l'elaborazione   di   applicativi   progettati   proprio   per   il   cosiddetto   “consumo   ”   dei   dati   provenienti   dai   web   services,   quindi   il   procedimento   deve   essere   eseguito   manualmente   dal   programmatore.   I   messaggi   forniti   da   questi   servizi,   seguono   la   struttura   dell’XML,   quindi,   un   qualsiasi   programma   che   li   vorrà   utilizzare,   dovrà   eseguire   un'analisi   del   messaggio,   prelevando   le   informazioni   utili   dal   messaggio  inviato  (parsing).   L'XML  utilizza  dei  marcatori,  chiamati  tag,  per  assegnare  una  semantica  al  testo.  È  molto  rigido  sulla   sintassi  da  seguire  rispetto  all'HTML  ed  è  pertanto  necessario  rispettare  alcune  regole:   ⇒ I  tag  non  possono  iniziare  con  numeri  o  caratteri  speciali  e  non  possono  contenere  spazi;     ⇒ I  tag  devono  essere  bilanciati,  ovvero  non  sono  consentiti  errori  di  annidamento.   ⇒ È  un  linguaggio  case  sensitive  quindi  i  tag  scritti  con  lo  stesso  nome,  ma  con  caratteri  maiuscoli   o  minuscoli  risultano  durante  il  parsing  essere  diversi.      L'utente   che   vorrà   quindi   leggere   un   determinato   messaggio   dovrà   far   eseguire   al   programma   un’analisi  di  ogni  singolo  tag,  conoscendo  a  priori   la  sua  struttura  e  la  sintassi  della  stringa  di  richiesta   da  inviare  al  server  per  ottenere  una  risposta  corretta.           3-­‐32  
  • 33.
        Figura  7:  In  alto:  esempio  di  request  In  basso:  response    del  web  service   Per   permettere   la   lettura   dei   messaggi   XML   provenienti   da   questi   servizi,   in   questo   progetto   è   stato   scelto   di   utilizzare   la   classe   NSXmlParser   che   rende   disponibili   metodi   per   la   lettura   e   l’analisi   dei   messaggi  XML.   Per  rendere  operativa  un'applicazione  che  legga  un  messaggio  da  web  service,  si  rende  necessaria  la   creazione   di   una   classe   che   possa   replicare   la   struttura   dei   dati   e   degli   attributi   prelevati   da   XML   in   modo   tale   da   renderli   fruibili   dal   programma   cosicché   ogni   sua   istanza   rappresenti   un   elemento   del   documento.   #import <Foundation/Foundation.h> @interface TagPoint : NSObject { @private NSString *namePoint; @private NSString *descriptPoint;//aggiunto ora @private NSNumber *latPoint; @private NSNumber *longitPoint; @private NSString *urlWiki; } @property (nonatomic,retain) NSString *namePoint; @property (nonatomic,retain) NSString *descriptPoint; @property (nonatomic,retain) NSNumber *latPoint; @property (nonatomic,retain) NSNumber *longitPoint; -(id)init; -(void) setLatPoint:(NSNumber *)lat; -(void) setLongitPoint:(NSNumber *)longit; -(void) setNamePoint:(NSString *) name; -(void) setDescriptionPoint:(NSString *)descript; -(void) setURLWiki:(NSString *)link -(void) setLatPoint:(NSNumber *)lat; -(void) setLongitPoint:(NSNumber *)longit;   3-­‐33  
  • 34.
    -(void) setNamePoint:(NSString *)name; -(void) setDescriptionPoint:(NSString *)descript; #import "TagPoint.h" @implementation TagPoint @synthesize namePoint, descriptPoint, urlWiki, latPoint, longitPoint; //inizializzo i field interni -(id)init { namePoint = [[NSString alloc] init]; descriptPoint =[[NSString alloc]init]; urlWiki = [[NSString alloc]init]; latPoint = [[NSNumber alloc] init]; longitPoint = [[NSNumber alloc] init]; return self; } -(void) setLatPoint:(NSNumber *)lat { latPoint = lat; } -(void) setLongitPoint:(NSNumber *)longit { longitPoint = longit; } -(void) setNamePoint:(NSString *) name { namePoint = name; } -(void) setDescriptionPoint:(NSString *)descript { descriptPoint = descript; } Codice  5:  header  e  implementazione  del  file  per  contenere  gli  elementi  XML   3.3.5.1 Parsing  del  messaggio   Per  eseguire  il  parsing  del  messaggio  XML  ricevuto  da  un  generico  web  service,  deve  essere  creata  la   stringa  di  “request”  ovvero  un’istanza  della  classe  NSURL  che  è  quella  delegata  a  comporre  la  richiesta   da   inviare   al   web   service,   poi   successivamente,   deve   essere   creato   l’istanza   dell’oggetto   che   servirà   ad   analizzare   il   messaggio   di   risposta,  ovvero  della  classe  NSXmlParser  che  è  inizializzata   con   l’oggetto   di   tipo  NSURL  creato  precedentemente.   A   questo   punto   il   programmatore   potrà   impostare   la   proprietà   di   delegate   dell’oggetto   di   tipo   NSXmlParser   inizializzato   in   precedenza,   con   un’istanza   di   una   classe   che   implementi   il   protocollo   NSXmlParserDelegate  che  serve  ad  eseguire  il  parsing  del  messaggio.   NSURL *url = [NSURL URLWithString:[NSString   3-­‐34  
  • 35.
    stringWithFormat:@"http://ws.geonames.org/findNearbyWikipedia?lat=%@&lng=%@",latStr ,longitStr]]; NSXMLParser *parser =[[NSXMLParser alloc] initWithContentsOfURL:url]; [parser setDelegate:self]; [parser parse]; [parser autorelease];     Il   protocollo   NSXmlParserDelegate   dovrà   contenere   dei   metodi   che   potranno   oppure   non,   essere   implementati,  tra  i  quali,  i  più  rilevanti  risultano  essere:  :   ⇒ -­(void)parser:(NSXMLParser  *)parser  didStartElement:(NSString  *)elementName   namespaceURI:(NSString  *)  namespaceURI  qualifiedName:(NSString  *)qName   attributes:  (NSDictionary  *)attributeDict ⇒ -­(void)parser:(NSXMLParser  *)parser  foundCharacters:(NSString  *)string   ⇒ -­(void)parser:(NSXMLParser  *)parser  didEndElement:(NSString  *)elementName   namespaceURI:(NSString  *)namespaceURI  qualifiedName:(NSString  *)qName     Il  primo  metodo  sarà  richiamato  quando  s’inizierà  il  parsing  del  messaggio,  con  lo  scopo  di  individuare   le  “aperture”  di  nuovi  tag,  e  inizializzare  le  eventuali  istanze  di  classi  usate  durante  il  parsing.   A   questo   punto   il   programma   richiamerà   il   secondo   metodo   che   riconoscerà   i   valori   dei   tag   e   li   assocerà  alla  variabile  di  tipo  NSDictionary.   Quando   poi   il   programma   riconoscerà   la   fine   di   un   tag   allora   richiamerà   l’ultimo   metodo   il   quale   assegnerà  i  valori  letti  ad  esempio  a  un  array  di  memorizzazione  temporanea  dei  dati  che  potrà  essere   utile  per  elaborazioni  dei  dati  successive.   3.3.6 Il  frame  work  Mapkit   Queste   librerie   permettono   di   usufruire   delle   funzionalità   e   della   visualizzazione   delle   mappe   similmente  a  quello  che  avviene  già  nell’applicazione  preinstallata  nell’Iphone.  Grazie  a  questo  frame   work   è   possibile   delegare   allo   sviluppatore   la   creazione   di   viste   personalizzate   della   mappa   oppure   gestire  le  annotazioni,  fornendo  un  valido  strumento  di  sviluppo  di  applicazioni  al  programmatore.   3.3.6.1 La  classe  MKMapView   E’   la   classe   principale   della   libreria   Mapkit   ed   è   derivata   dalla   classe   UIKit,   cosicché   è   facilmente   implementabile  nelle  classi  usate  principalmente  per  elaborare  oggetti  grafici.   Per  un  corretto  funzionamento  del  progetto  in  cui  si  vuole  includere  questo  frame  work,  è  necessario   dichiarare  espressamente  l’uso  di  questa  libreria  nella  classe  in  cui  la  si  implementa,  aggiungendo  sia   all’header  della  classe  il  codice  <MapKit/MapKit.h>,  sia  nelle  impostazioni  del  progetto.     A  questo  punto  potrò  procedere  con  la  dichiarazione  dell’istanza  di  questa  classe,  impostando  anche  le   sue  proprietà:   MKMapView *mapView = [[[MKMapView alloc] initWithFrame: [UIScreen mainScreen].applicationFrame] autorelease]; [self.view addSubview:mapView];   3.3.6.2 La  structure  MKCoordinateRegion   Questo   elemento   della   Mapkit   è   una   structure   (struttura   dati),   che   contiene   al   suo   interno   gli   elementi   necessari  al  momento  del  caricamento  di  una  mappa    quali    il  centro  della  mappa  contenuti  nella  struct   CLLocationCoordinate2D(latitudine,   longitudine)   e   lo   zoom   contenuto   invece   nella   struct       3-­‐35  
  • 36.
    MKCoordinateSpan   composto   da   due   valori   di   tipo   CLLocationDegrees   corrispondenti   a   valori   di   tipo   double.     typedef struct { CLLocationCoordinate2D center; MKCoordinateSpan span; } MKCoordinateRegion; typedef struct { CLLocationDegrees latitudeDelta; CLLocationDegrees longitudeDelta; } MKCoordinateSpan;     3.3.6.3 Il  protocollo  MKAnnotation   I  punti  che  si  vogliono  visualizzare  sulla  mappa  vanno  sotto  il  nome  di  “annotations”.   Un’annotation  è  composta  da  un  data  model  che  specifica  il  titolo,  il  sottotitolo,  i  valori  di     latitudine/longitudine  del  punto  e  una  “view”  che  altro  non  è  che  la  rappresentazione  del  data  model.   Il  protocollo  MKAnnotation  descrive  quindi  il  modello  della  descrizione  del  punto:   @protocol MKAnnotation <NSObject> @property (nonatomic, readonly) CLLocationCoordinate2D coordinate; @optional - (NSString *)title; - (NSString *)subtitle; @end     In   sintesi,   questo   protocollo   stabilisce   che   ogni   “annotation”   può   essere   abilitata   a   specificare   le   sue   coordinate  ed  eventualmente  impostare  il  titolo  e  il  sottotitolo.     Per   creare   quindi   una   classe   per   le   annotazioni   di   una   mappa,   si   dovrà   obbligatoriamente   implementare  questo  protocollo,  come  evidenziato  nel  seguente  esempio:     @interface MyAnnotation : NSObject<MKAnnotation> { CLLocationCoordinate2D coordinate; NSString *name; NSString *title; NSString *descr; NSString *link; } @property (nonatomic, readonly) CLLocationCoordinate2D coordinate; @property (nonatomic,retain) NSString *name; @property (nonatomic,retain) NSString *title; @property (nonatomic,retain) NSString *descr;   3-­‐36  
  • 37.
    @property (nonatomic, retain)NSString*link; • (id) initWithCoords:(CLLocationCoordinate2D) coords name:(NSString*) inputName descr:(NSString*) inputDescr link:(NSString*) inputLink ; @implementation MyAnnotation @synthesize coordinate, name, title, descr, link; - (id) initWithCoords:(CLLocationCoordinate2D) coords name:(NSString*) inputName descr:(NSString*)inputDescr link:(NSString*)inputLink { self = [super init]; if (self != nil) { coordinate = coords; self.name = inputName; self.title = inputName; self.descr = inputDescr; self.link = inputLink; } return self; } @end Codice  6:  Esempio  d’implementazione  del  protocollo  MKAnnotation   3.3.6.4 La  classe  MKAnnotationView   E’  la  classe  che  si  occupa  della  visualizzazione  delle  annotazioni  sulla  mappa.   Per   rendere   possibile   l’iterazione   dell’istanza   di   questa   classe   con   la   mappa   è   necessario   settare   la   sua   proprietà  di  delegate  sull’istanza  della  vista  della  mappa  ed  avere  un  metodo  che  restituisca  un  oggetto   di  tipo  UIView  per  ogni  “annotation”  ottenuta.   @property (nonatomic, assign) id <MKMapViewDelegate> delegate;   (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;   Codice  7:  dichiarazione  della  proprietà  delegate   3.3.6.5 La  classe  MKUserLocation   Questa  classe  è  usata  per  la  visualizzazione  della  localizzazione  dell’utente.       3.3.6.6 La  classe  MKPinAnnotationView     Deriva   dalla   classe   MKAnnotationView   e   rappresenta   il   “pin”   grafico   in   una   mappa,   ossia   quell'elemento   che   segnala   un   punto   d’interesse   dell'utente   sulla   mappa   disegnata   nella   vista,   come   mostrato  in  questo  esempio  di  codice:     ..   3-­‐37  
  • 38.
    MKPinAnnotationView* annView =(MKPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier]; if(nil == annView) { annView = [[[MKPinAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease]; } [annView addObserver:self forKeyPath:@"selected" options:NSKeyValueObservingOptionNew context:GMAP_ANNOTATION_SELECTED]; [annView setPinColor:MKPinAnnotationColorGreen]; ….   Codice  8:  esempio  di  implementazione  della  MKPinAnnotationView       Figura  8:  Esempio  grafico  della  classe  MKPinAnnotationView     3.3.7 La  libreria  dell’”Augmented  Reality”(ARKit)   L'Iphone  ARKit  è  un  progetto  open  source,  pubblicato  verso  la  metà  di  Luglio  2009,  composto  da  un   set  di  classi  che  forniscono  alle  applicazioni  in  cui  è  implementato,  il  modello  della  “Realtà  Aumentata”.     Questa   caratteristica   permette   di   visualizzare   delle   informazioni   aggiuntive   all'osservatore   sull’ambiente   a   lui   circostante   tramite   la   fotocamera   dell'Iphone   che   è   utilizzata   come   mezzo   per   la   localizzazione  dei  punti  di  interesse  presenti.   Questo   risultato   è   possibile   grazie   all'iterazione   fra   più   periferiche   già   presenti   nell'Iphone:   il   ricevitore  GPS,  la  bussola  e  l'accelerometro,  come  mostrato  nello  schema  sottostante.         3-­‐38  
  • 39.
    Figura  9:  Schema  di  funzionamento  libreria  AR   ⇒ Il  ricevitore  GPS  servirà  a  ottenere  la  posizione  istantanea  del  telefono;   ⇒ La   bussola   per   carpire   la   posizione   dell'utente   in   modo   tale   da   gestire   il   layer   virtuale   sovrapposto  all'obiettivo,  relativo  ai  punti  d’interesse;   ⇒ L'accelerometro  per  ottenere  l'orientamento  relativo  dell'utente  (inclinazione  dell'Iphone);   ⇒ La  fotocamera  per  far  interagire  l'Iphone  con  l'ambiente  reale.     3.3.7.1 Struttura  della  libreria     Figura  10:  Organizzazione  della  libreria  AR   La   classe   è   composta   di   due   view   controller,   l’ARViewController   e   l’ARGeoViewController,   in   cui   il   primo   è   derivato   direttamente   dalla   classe   UIViewController,   che   si   occupa   della   gestione   dell’interfaccia  grafica,  mentre  il  secondo  è  figlio  dell’ARViewController.   L’ARViewController   implementa   i   protocolli   per   la   gestione   dell'accelerometro   (UIAccelerometerDelegate),   del   ricevitore   GPS   (CLLocationManagerDelegate)   e   dichiara   un   suo   protocollo   (ARViewDelegate)   in   cui   è   definito   un   metodo   (viewForCoordinate:)   che   ha   in   ingresso   un'istanza   della   classe   ARCoordinate   e   che   ritorna   un   elemento   grafico   di   tipo   UIView   che   serve   a   “costruire”  l’interfaccia  grafica  finale  per  la  visualizzazione  dell’”Augmented  Reality”.   Quest’ultima   classe,   si   occupa   della   gestione   dell'UIImagePickerController   che   è   il   controller   usato   per   gestire   l'obiettivo   fotografico   dell'Iphone,   dell'inizializzazione   del   ricevitore   GPS,   della   bussola   e   costruisce  in  maniera  gerarchica  la  visualizzazione  della  maschera,  impostando  l'area  del  display  del   telefono,  del  caricamento  dei  punti  d’interesse  nella  memoria  e  della  loro  visualizzazione.   La   sua   figlia,   ossia   la   classe   ARGeoViewController,   aggiunge   ai   metodi   già   implementati   dalla   classe   madre,   la   localizzazione   del   centro   delle   coordinate   corrispondente   alla   posizione   dell’utente   nello   spazio.   Le   classi   invece   ARCoordinate   e   ARGeoCoodinate,   fungono   da   “contenitori”   dei   dati   memorizzati   attraverso  i  view  controllers,  fornendo  dei  metodi  per  la  loro  elaborazione.         4 REALIZZAZIONE       4-­‐39  
  • 40.
    4.1 Specifiche   L’obiettivo   del   progetto   è   di   sviluppare   e   realizzare   un   applicativo   in   grado   di   riconoscere   tramite   l’obiettivo   della   macchina   fotografica   integrata   nell’Iphone   i   punti   d’interesse,   inseriti   dall’utente   nella   memoria   del   telefono   e   non,   nelle   vicinanze   dell’utente,   integrando   al   tempo   stesso   nel   programma   alcuni   elementi   caratteristici   di   un’applicazione   di   navigazione,   quali   ad   esempio   la   visualizzazione   della   mappa,   la   tracciatura   del   percorso   compiuto   durante   un   intervallo   di   tempo   o   anche   la   localizzazione  sulla  mappa  dei  punti  d’interesse  dell’utente.   Come   specifica   imposta   in   un   secondo   momento,   è   stata   quella   di   creare   un   sistema   “leggero”   in   termini   di   risorse   richieste   al   sistema,   in   quanto   si   doveva   tenere   conto   delle   prestazioni   ridotte   del   dispositivo   mobile   sul   quale   si   vanno   a   caricare   i   dati,   cercando   di   colmare   queste   lacune   con   lo   sfruttamento  della  rete,  trattata  come  una  risorsa  aggiuntiva  per  l’estrazione  dei  dati  da  elaborare.   Per  realizzare  quindi  un  sistema  di  questo  tipo  si  è  dovuto  focalizzare  l’attenzione  sugli  elementi  che   avrebbero  caratterizzato  questo  software:     ⇒ Un  database  di  memorizzazione  dei  punti  d’interesse  specificati  dall’utente;   ⇒ L’integrazione  della  fotocamera  nell’applicativo;   ⇒ L’implementazione  dell’”Augmented  Reality”;     ⇒ L’utilizzo  della  rete  per  il  caricamento  di  dati  provenienti  dai  web  services;   ⇒ La   visualizzazione   di   una   mappa   e   la   disponibilità   di   funzioni   tipiche   dei   software   di   navigazione.   Le  motivazioni  di  queste  scelte  sono  state  le  seguenti:   • La  necessità  di  avere  un  sistema  di  tabelle  per  la  memorizzazione  interna  dei  punti  d’interesse   consente  al  programma  stesso  di  riconoscerli,  permettendo  al  sistema  di  sfruttare  in  maniera   corretta  le  potenzialità  della  “realtà  aumentata”  implementata  sull’Iphone.   • La   gestione   della   fotocamera   integrata   nel   programma   consente   all’utente   di   non   dover   uscire   dall’applicativo   per   scattare   una   foto   al   suo   punto   d’interesse   e   anche   in   questo   caso   di   interagire  con  le  librerie  dell’Augmented  Reality;   • L’uso  della  realtà  aumentata  permette  di  soddisfare  gli  obiettivi  del  progetto  interponendo  tra   l’osservatore   e   la   fotocamera   del   dispositivo,   un   “layer”   che   consentirà   di   indicare   e   riconoscere  i  punti  d’interesse.   • L’utilizzo  dei  web  services  in  linea  generica  permetterà  al  programma,  una  volta  concluso,  di   sfruttare  la  rete  come  un’enorme  fonte  di  dati,  integrando  le  informazioni  già  in  suo  possesso   con  quelle  presenti  su  database  remoti.   4.1.1 Memorizzazione  persistente  dei  punti  d’interesse  e  integrazione  nel  programma  dell’uso   della  fotocamera         4-­‐40  
  • 41.
      Figura  11:  Rappresentazione  del  sistema  iniziale  di  memorizzazione   4.1.1.1 Un  approccio  alla  memorizzazione  dei  dati   La   base   di   partenza   è   stata   un   database,   contenente   una   sola   tabella   che   avrebbe   memorizzato   solo   delle   ipotetiche   informazioni   in   forme   testuali   e   numeriche   relative   alle   coordinate   geografiche   e   le   descrizioni   di   eventuali   punti   d’interesse.   Per   rendere   fruibili   i   dati,   si   sono   dovute   creare   anche   le   relative  interfacce  grafiche  in  modo  da  permettere  le  iterazioni  fra  la  persona  e  il  programma.   Per  costruirle,  ci  si  è  appoggiati  all’Interface  Builder,  creando  un  insieme  di  form,  ognuna  delle  quali   progettata  per  visualizzare,  aggiornare,  inserire  o  cancellare  i  dati  presenti  in  memoria.   Questo   sistema   però   è   risultato   essere   incompleto   perché   mancava   di   un’ulteriore   caratterizzazione   delle  informazioni  sui  punti  d’interesse:  la  possibilità  di  associare  a  un  punto  una  foto.   Di   conseguenza,   allora   al   database   esistente,   si   è   aggiunta   un’altra   tabella   con   lo   scopo   di   utilizzarla   nella  memorizzazione  di  un’eventuale  foto  per  il  punto  d’interesse  stesso.   4.1.1.2 Il  sistema  finale  di  memorizzazione  dei  dati   La  memorizzazione  dei  dati  è  da  considerarsi  come  un  elemento  necessario  poiché  senza  di  essa,  non   ci   sarebbe   la   possibilità   di   soddisfare   tutte   le   specifiche   stabilite   all’inizio   del   progetto   e   soprattutto   poter   usufruire   dei   dati   per   elaborazioni   successive,   come   ad   esempio   l’implementazione   dell’Augmented  Reality  o  la  visualizzazione  dei  punti  su  una  mappa.   Il  sistema  di  memorizzazione  finale  sarà  quindi  schematizzato  come  quello  rappresentato  nella  figura   12.     4-­‐41  
  • 42.
      Figura  12:  sistema  di  memorizzazione  finale   Il  frame  work  utilizzato  per  la  gestione  delle  tabelle  è  stato  il  CoreData  nel  quale  sono  state  create  due   tabelle:   ⇒ Photo   ⇒ PhotoPoint   La   tabella   Photo   è   quella   in   cui   saranno   contenuti   i   dati   di   tipo   numerico   e   testuale   del   punto   d’interesse   dell’utente,   mentre   la   tabella   PhotoPoint   sarà   quella   collegata   alla   prima   e   conterrà   l’immagine  del  punto  stesso.   Per   creare   un   programma   di   questo   tipo,   come   prima   cosa,   si   è   incluso   nelle   impostazioni   iniziali   di   creazione,   il   frame   work   CoreData,   poi   in   seguito   si   sono   create   le   due   tabelle   appena   menzionate   attraverso  l’editor  dell’Xcode.   Seguendo   questi   passaggi,   il   tool   di   sviluppo   agevolerà   il   lavoro   dello   sviluppatore   impostando   nelle   classi  create  di  default,  tutti  i  metodi  necessari  a  lavorare  sulle  tabelle  e  a  ricavare  il  contesto.       4-­‐42  
  • 43.
      Figura  13:  creazione  del  progetto  includendo  il  CoreData   Nella  finestra  “Group  &  Files”,  nella  cartella  “Classes”  si  è  creato  un  gruppo  nominato  “Model”,  dove  è   stato  creato  tramite  l’editor,    il  database  “photo.xcdatamodel”e  dove  all’interno  dello  stesso  poi  sono   state  inserite  le  due  tabelle  necessarie  nel  progetto:  Photo  e  PhotoPoint,     Tenendo   conto   delle   specifiche   precedentemente   imposte,   nella   tabella   Photo,   si   sono   inseriti   i   seguenti  campi:   I. namePhoto     II. latitudePhoto   III. longitudePhoto   IV. descriptionPhoto   V. photoThumbnailImage   Il  primo  indicherà  il  nome  del  punto  e  sarà  di  tipo  “String”  come  l’attributo  “descriptionPhoto”,  mentre   i   campi   “latitudePhoto”   e   “longitudePhoto”   saranno   di   tipo   “Float”   e   l’ultimo,   ovvero   il   “photoThumbnailImage”  sarà  di  tipo  “Transformer”.   Nella   tabella   PhotoPoint   sarà   contenuto   solo   un   attributo   di   tipo   “Transformer”   che   conterrà   l’immagine  da  associare  al  punto:   I. photoPoint     4-­‐43  
  • 44.
    Le  due  tabelle  sono  state   collegate   creando  una  relazione  di  tipo  uno  a  uno  attraverso   l’identificazione   nelle  due  entità  di  un  campo  di  tipo  “Relationships”  nominato  nella  prima  come  “photoPoint”  e  nella   seconda  come  “photo”.     In  seguito  poi,  sono  stati  collegati  tramite  l’editor  come  presentato  nella  figura  sottostante.     Figura  14:  Editor  per  costruire  il  modello  xcdatamodel   Sempre   all’interno   del   gruppo   “Model”,   si   sono   create   e   associate   due   classi,   chiamate   Photo   e   PhotoPoint,   derivanti   dall’oggetto   NSManagedObject   con   lo   scopo   di   gestire   le   due   tabelle   appena   create  e  in  cui  al  loro  interno  sono  state  inserite  le  proprietà  corrispondenti  ai  campi  di  ogni  singola   entità.     Tenendo   presente   che   il   tipo   di   proprietà   della   classe   dovrà   essere   compatibile   con   quello   corrispondente  della  tabella,  l’attributo  di  tipo  String  della  tabella  sarà  passato  nella  classe  con  il  tipo   NSString,   il   tipo   Float   con   la   proprietà   di   tipo   NSNumber;   mentre   i   campi   di   tipo   “Relationships”,   nella   classe,  saranno  descritti  da  una  proprietà  corrispondente  al  tipo  di  classe  sul  quale  quella  determinata   relazione  andrà  a  collegarsi(ad  esempio:  in  Photo,  la  relazione  verso  PhotoPoint  sarà  descritta  da  una   proprietà  della  classe  di  tipo  PhotoPoint  e  viceversa  ).   #import <Foundation/Foundation.h> #import "Photo.h" #import <CoreData/CoreData.h> #import "PhotoPoint.h" @class PhotoPoint; @implementation Photo @interface UIImageToDataTransformer: NSValueTransformer { @dynamic namePhoto;   4-­‐44  
  • 45.
    @dynamic latitudePhoto; } @dynamic longitudePhoto; @end @dynamic descriptionPhoto; @dynamic photoThumbnailImage; @interface Photo : NSManagedObject { @dynamic photoPoint; } @end @property (nonatomic,retain) NSString @implementation *namePhoto; UIImageToDataTransformer @property (nonatomic,retain) NSNumber *latitudePhoto; @property (nonatomic,retain) NSNumber + (BOOL)allowsReverseTransformation { *longitudePhoto; return YES; @property (nonatomic,retain) NSString } *descriptionPhoto; @property (nonatomic,retain) id + (Class)transformedValueClass { photoThumbnailImage; return [NSData class]; @property (nonatomic,retain) PhotoPoint } *photoPoint; - (id)transformedValue:(id)value { @end NSData *data =   UIImagePNGRepresentation(value); return data; } - (id)reverseTransformedValue:(id)value { UIImage *uiImage = [[UIImage alloc] initWithData:value]; return [uiImage autorelease]; } @end   Codice  9:  interfaccia  e  implementazione  della  classe  Photo   #import <Foundation/Foundation.h> #import "PhotoPoint.h" @class Photo; @implementation PhotoPoint @interface PhotoPoint : NSManagedObject { @dynamic photo; } @dynamic photoPoint;   4-­‐45  
  • 46.
    @property (nonatomic,retain) Photo*photo; @end @property (nonatomic, retain) id photoPoint;   @end   Codice  10:  Interfaccia  e  implementazione  della  classe  PhotoPoint   Per   quanto   concerne   la   descrizione   della   proprietà   di   tipo   “Transformable”   che   avrà   come   valore   UIImageToDataTransformer,   nell’interfaccia   la   si   dovrà   dichiarare   tramite   l’oggetto   UIImageToDataTransformer   che   deriverà   da   NSValueTransformer   e   che   servirà   a   convertire   l’immagine  in  una  forma  di  dato  memorizzabile  nella  tabella.       4.1.1.2.1 Impostazione  dei  view  controller   Per  visualizzare,  inserire,  modificare  o  eliminare  i  dati  presenti  nel  programma,  si  è  avuto  bisogno  di   creare  svariati  view  controller,  derivanti  tutti  dalla  classe  UIViewController.     Nel  caso  di  questa  prima  parte,  si  sono  creati  cinque  view  controller  per  coprire  i  diversi  compiti  del   sistema  di  memorizzazione:   I. AddPhotoViewController   II. PhotoDetailViewController   III. PhotoViewController   IV. EditingPhotoViewController   V. RootViewController   Il   primo   controller   sarà   utilizzato   per   inserire   nel   programma   un   nuovo   punto   d’interesse,   il   “PhotoDetailViewController”  sarà  usato  per  visualizzare  il  dettaglio  di  ogni  punto  d’interesse  quando   l’utente   partendo   dal   controller   iniziale   (RootViewController)   vorrà   visualizzare   i   dettagli;   il   “PhotoViewController”   servirà   a   rappresentare   una   foto   a   schermo   intero;   il   penultimo   servirà   a   modificare  le  informazioni  di  un  punto  già  inserito  mentre  il  “RootViewController”  fungerà  da  base  per   tutto  il  sistema,  coordinando  l’attivazione  globale  di  tutte  le  form  .   4.1.1.2.1.1 AddPhotoViewController   Il  primo  controller  a  essere  stato  sviluppato  è  stato  questo,  poiché  è  quello  che  consente  di  aggiungere   i  dati  alle  tabelle.   Esso  è  derivato  dall’UIViewController  come  tutte  le  altre  form  che  saranno  analizzate  e  implementerà  i   protocolli   di   UITextFieldDelegate,   UITextViewDelegate,   UIImagePickerControllerDelegate   e   CLLocationManagerDelegate.    I   primi   due   serviranno   a   includere   alcuni   dei   metodi   propri   degli   oggetti   della   libreria   grafica   UITextField   e   UITextView   (in   questo   caso,   saranno   sfruttati   -­‐ (BOOL)textFieldShouldReturn:(UITextField   *)textField{}   per   disabilitare   la   tastiera   quando   l’utente   premerà  il  tasto  “return”  sulla  textfield  e  -­‐(BOOL)textViewShouldEndEditing:(UITextView  *)textView{   }  per  la  UITextView),  il  delegate  dell’UIImagePickerController  che  implementerà  i  metodi  per  gestire  le   librerie   di   immagini   e   la   stessa   fotocamera,   presenti   nell’Iphone,   come   ad   esempio   i   metodi   - (void)imagePickerController:(UIImagePickerController   *)picker   didFinishPickingImage:(UIImage     *)selectedImage   editingInfo:(NSDictionary     *)editingInfo   {}   e   -­‐   (void)imagePickerControllerDidCancel:(UIImagePickerController  *)picker  {}  usati  per  gestire  il  primo   l’editing  dell’immagine  ed  il  secondo  per  l’annullamento  di  una  determinata  azione  su  questo  elemento   grafico  ed  infine  il  protocollo  CLLocationManagerDelegate  che  gestirà  il  ricevitore  GPS  integrato.   Essendo  questo  controller  collegato  direttamente  a  un’interfaccia  visuale,  si  sono  dichiarati  gli  oggetti   grafici   che   saranno   utilizzati,   prima   nell’interfaccia   della   classe,   poi   inizializzandoli   ed   elaborandoli   nell’implementazione.     4-­‐46  
  • 47.
      4.1.1.2.1.1.1 Funzionamento   Lo  scopo  di  questo  controller  è  di  dare  la  possibilità  all’utente  di  inserire  dei  dati  nuovi  in  memoria.   I   campi   di   testo   riguardanti   le   coordinate   di   latitudine   e   longitudine   sono   impostati   durante   il   caricamento   del   view   controller   leggendo   i   rispettivi   valori   dai   metodi   implementati   nel   protocollo   CLLocationManagerDelegate,  mentre  gli  altri,  ovvero  quelli  della  descrizione  e  della  scelta  della  foto  da   associare,  saranno  modificabili  dall’utente.     Potrà   essere   eseguita   la   scelta   della   foto   grazie   all’invocazione   dei   metodi   presenti   nel   protocollo   UIImagePickerDelegate   che   gestiranno   la   libreria   fotografica   e   alla   classe   di   tipo   UIViewController   che   li  richiamerà.   A  questo  punto  l’utente  potrà   ⇒ Salvare   il   tutto   andando   a   richiamare   il   metodo   che   nel   codice   descritto   poco   più   sotto   prende   il  nome  di  “save”;   ⇒  Annullare  tutte  le  sue  azioni  invocando  sempre  da  interfaccia  grafica  il  metodo  “cancel”;   ⇒ Scegliere  le  foto  già  presenti  nella  libreria;   ⇒  Gestire   direttamente   la   fotocamera   per   scattare   nuove   foto   richiamando   il   metodo   “cameraClick:”.    Andando  ad  analizzare  più  approfonditamente  il  codice  dei  primi  due  metodi,  si  vedrà  che  nel  metodo   “save”  sarà  ripreso  il  contesto  dell’applicazione,  poi  verranno  letti  i  valori  dei  singoli  campi  di  testo  e   associati  alla  classe  “Photo”  e  solo  alla  fine  saranno  salvati  nella  tabella.    Nel   metodo   “cancel”   invece   sarà   recuperato   il   contesto   come   nel   primo   caso,   ma   al   contrario,   verrà   cancellata  quella  determinata  istanza  della  classe  “Photo”  attraverso  il  metodo  “deleteObject:”.   Mentre   per   la   scelta   di   foto   già   memorizzate   nell’Iphone,   l’utente   invocherà   il   metodo   “photoButtonPressed”  che  andrà  a  gestire  direttamente  la  libreria  fotografica  con  l’aiuto  del  protocollo   UIImagePickerDelegate.   Se  invece  vorrà  scattare  una  nuova  foto,  dall’interfaccia  grafica  dovrà  invocare  il  metodo  “cameraClick”   che   inizializzerà   e   aprirà   il   controller   “CameraViewController”,   il   cui   funzionamento   sarà   coordinato   dalla   classe   “ImmaginePickerDelegate”   che   implementerà   il   protocollo   “UIImagePickerControllerDelegate”  con  i  relativi  metodi  stabiliti  per  la  gestione  della  fotocamera.     #import <UIKit/UIKit.h> #import <CoreLocation/CoreLocation.h>//GPS @class Photo; @interface AddPhotoViewController : UIViewController<UITextFieldDelegate, UITextViewDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, CLLocationManagerDelegate> { Photo *photo; UITextField *namePhotoTxt; UITextField *latitudePhotoTxt; UITextField *longitudePhotoTxt;   4-­‐47  
  • 48.
    UITextView *descriptionPhotoTxt; UIButton *photoButton; UIButton *cameraButton; UIViewController *provaView; CLLocationManager *locationManager; CLLocation *startingPoint; //toolbar per le foto UISegmentedControl *segmentControl; //UIToolbar *toolbar; } @property (retain, nonatomic) CLLocationManager *locationManager; @property (retain, nonatomic) CLLocation *startingPoint; @property (nonatomic,retain) Photo *photo; @property (nonatomic,retain) IBOutlet UITextField *namePhotoTxt; @property (nonatomic,retain) IBOutlet UITextField *latitudePhotoTxt; @property (nonatomic,retain) IBOutlet UITextField *longitudePhotoTxt; @property (nonatomic,retain) IBOutlet UITextView *descriptionPhotoTxt; @property (nonatomic, retain) IBOutlet UIButton *photoButton; @property (nonatomic, retain) IBOutlet UIButton *cameraButton; @property (nonatomic, retain) UIViewController * provaView; - (IBAction)photoButtonPressed; - (IBAction)cameraClick:(id) sender; @end #import "AddPhotoViewController.h" #import "PhotoViewController.h" #import "CameraViewController.h" #import "Photo.h" @implementation AddPhotoViewController @synthesize photo, namePhotoTxt, latitudePhotoTxt, longitudePhotoTxt, descriptionPhotoTxt; @synthesize photoButton, cameraButton; @synthesize locationManager, startingPoint; #pragma mark - #pragma mark lifecycle - (void)viewDidLoad { [super viewDidLoad];   4-­‐48  
  • 49.
    //inizializzazione del GPS self.locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; locationManager.desiredAccuracy = kCLLocationAccuracyBest; self.title=@"Inserisci dettagli"; //dichiarazione dei bottoni UIBarButtonItem *cancelButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(save)]; //inserisco i bottoni di cancel e salvataggio nel NavController self.navigationItem.leftBarButtonItem = cancelButton; [cancelButton release]; self.navigationItem.rightBarButtonItem = saveButton; [saveButton release]; //avvio ricezione segnale GPS [locationManager startUpdatingLocation]; [photoButton setImage:photo.photoThumbnailImage forState:UIControlStateNormal]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [photoButton setImage:photo.photoThumbnailImage forState:UIControlStateNormal]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (void)viewDidUnload { [locationManager stopUpdatingLocation]; } - (void)dealloc { [locationManager release]; [startingPoint release]; [photo release]; [namePhotoTxt release]; [latitudePhotoTxt release]; [longitudePhotoTxt release]; [descriptionPhotoTxt release]; [photoButton release]; [cameraButton release];   4-­‐49  
  • 50.
    [super dealloc]; } #pragma mark- #pragma mark Button's Method - (void)cancel { [photo.managedObjectContext deleteObject:photo]; NSError *error = nil; if (![photo.managedObjectContext save:&error]) { exit(-1); // Fail } [self dismissModalViewControllerAnimated:YES]; } - (void)save { float latitude = [latitudePhotoTxt.text floatValue]; float longitude = [longitudePhotoTxt.text floatValue]; NSNumber *latitudeNumber = [NSNumber numberWithFloat:latitude]; NSNumber *longitudeNumber = [NSNumber numberWithFloat:longitude] //setup valori della classe Photo photo.namePhoto = namePhotoTxt.text; photo.latitudePhoto = latitudeNumber; photo.longitudePhoto = longitudeNumber; photo.descriptionPhoto = descriptionPhotoTxt.text; NSError *error = nil; if (![photo.managedObjectContext save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); exit(-1); } [self dismissModalViewControllerAnimated:YES]; } -(IBAction)cameraClick: (id)sender { CameraViewController *cameraViewController = [[CameraViewController alloc] initWithNibName:@"CameraViewController" bundle:[NSBundle mainBundle]]; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: cameraViewController]; [self.navigationController presentModalViewController:navController animated:YES]; [cameraViewController release]; } #pragma mark - #pragma mark Photo - (IBAction)photoButtonPressed { [namePhotoTxt endEditing:YES]; [descriptionPhotoTxt endEditing:YES];   4-­‐50  
  • 51.
    UIImagePickerController *imagePicker =[[UIImagePickerController alloc] init]; imagePicker.delegate = self; [self presentModalViewController:imagePicker animated:YES]; [imagePicker release]; } - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo { NSManagedObject* oldImage = (NSManagedObject *)photo.photoPoint if (oldImage != nil) { [photo.managedObjectContext deleteObject:oldImage]; } PhotoPoint *image = [NSEntityDescription insertNewObjectForEntityForName:@"PhotoPoint"inManagedObjectContext:photo.managed ObjectContext]; photo.photoPoint = image; [image setValue:selectedImage forKey:@"photoPoint"]; CGSize size = selectedImage.size; CGFloat ratio = 0; if (size.width > size.height) { ratio = 128.0 / size.width; }else { ratio = 130.0 / size.height; } CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height); UIGraphicsBeginImageContext(rect.size); [selectedImage drawInRect:rect]; photo.photoThumbnailImage = UIGraphicsGetImageFromCurrentImageContext(); [self dismissModalViewControllerAnimated:YES]; } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [self dismissModalViewControllerAnimated:YES]; } //disabilita la tastiera quando viene premuto il return -(BOOL)textFieldShouldReturn:(UITextField *)textField{ [namePhotoTxt resignFirstResponder]; return YES; } -(BOOL)textViewShouldEndEditing:(UITextView *)textView{ [descriptionPhotoTxt resignFirstResponder];   4-­‐51  
  • 52.
    return YES; } #pragma mark- #pragma mark CLLocationManagerDelegate Methods - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { //inizializzazione if (startingPoint == nil) self.startingPoint = newLocation; NSString *latitudeStr = [[NSString alloc] initWithFormat:@"%g ", newLocation.coordinate.latitude]; latitudePhotoTxt.text = latitudeStr; [latitudeStr release]; NSString *longitudeStr = [[NSString alloc] initWithFormat:@"%g ", newLocation.coordinate.longitude]; longitudePhotoTxt.text = longitudeStr; [longitudeStr release]; } - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { NSString *errorType = (error.code == kCLErrorDenied) ? @"Accesso negato" : @"Errore sconosciuto"; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Errore nella Localizzazione" message:errorType delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil]; [alert show]; [alert release]; } @end Codice  11:  Interfaccia  e  implementazione  di  AddViewController   #import <UIKit/UIKit.h> #import <Foundation/Foundation.h> #import "ImmaginePickerDelegate.h" @interface CameraViewController : @interface ImmaginePickerDelegate : UIViewController<UINavigationControllerDelegate> NSObject<UINavigationControllerDeleg { ate, UIImagePickerControllerDelegate> IBOutlet ImmaginePickerDelegate * { imgPickerDelegate; UIImage * selezionaImage; IBOutlet UIImageView * vistaImage; } } @property (nonatomic, retain) @property (nonatomic, retain) UIImage   4-­‐52  
  • 53.
    ImmaginePickerDelegate * imgPickerDelegate; * selezionaImage; @property (nonatomic, retain) UIImageView * vistaImage; @end - (IBAction) clickFoto: (id) sender;   @end   #import "CameraViewController.h" #import "ImmaginePickerDelegate.h" #import "ImmaginePickerDelegate.h" @implementation @implementation CameraViewController ImmaginePickerDelegate @synthesize imgPickerDelegate; @synthesize vistaImage; @synthesize selezionaImage; #pragma mark - - (void) imagePickerControllerDidCancel: #pragma mark LifeCycle (UIImagePickerController *) picker { // Implement viewDidLoad to do additional setup NSLog(@"cancel"); after loading the view, typically from a nib. [picker.parentViewController - (void)viewDidLoad { dismissModalViewControllerAnimated:Y [super viewDidLoad]; ES]; //dichiarazione dei bottoni [picker release]; UIBarButtonItem *cancelButton } =[[UIBarButtonItem alloc] - initWithBarButtonSystemItem:UIBarButtonSyste (void)imagePickerController:(UIImagePi mItemCancel target:self ckerController *) picker action:@selector(cancel)]; didFinishPickingMediaWithInfo:(NSDic self.navigationItem.leftBarButtonItem = tionary *) info { cancelButton; NSLog(@"fisso immagine"); [cancelButton release]; self.selezionaImage = if(!([UIImagePickerController (UIImage*)[info isSourceTypeAvailable:UIImagePickerControllerSo objectForKey:UIImagePickerController urceTypeCamera])) OriginalImage]; { [[NSNotificationCenter NSLog(@"Fotocamera non presente....uscita defaultCenter] dall'applicazione"); postNotificationName:@"immagine" UIAlertView * erroreAlert = [[UIAlertView object:nil]; alloc]initWithTitle:@"Errore nella fotocamera " [picker.parentViewController message:@"Fotocamera non dismissModalViewControllerAnimated:Y supportata!L'applicazione terminerà." delegate:nil ES]; cancelButtonTitle:nil otherButtonTitles:@"OK", [picker release]; nil]; } [erroreAlert show]; - (void) dealloc { [erroreAlert release]; [selezionaImage release]; //warning - terminate is undocumented api [super dealloc]; //[[UIApplication sharedApplication] }   4-­‐53  
  • 54.
    terminate]; } @end   NSLog(@"Sono in viewDidLoad"); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cambiaImage) name:@"immagine" object:nil]; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } - (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } - (void)dealloc { [super dealloc]; [vistaImage release]; [imgPickerDelegate release]; [ [NSNotificationCenter defaultCenter] removeObserver:self]; } - (void) cambiaImage { NSLog(@"Immagine cambiata!"); self.vistaImage.image = self.imgPickerDelegate.selezionaImage; } #pragma mark - #pragma mark Button's methods -(void) cancel{ [self dismissModalViewControllerAnimated:YES]; }   4-­‐54  
  • 55.
    - (IBAction) clickFoto:(id) sender { if(!([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSo urceTypeCamera])) { NSLog(@"Fotocamera non presente....uscita dall'applicazione"); UIAlertView * erroreAlert = [[UIAlertView alloc]initWithTitle:@"Errore nella fotocamera " message:@"Fotocamera non supportata!L'applicazione terminerà." delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [erroreAlert show]; [erroreAlert release]; //warning - terminate is undocumented api //[[UIApplication sharedApplication] terminate]; } else { UIImagePickerController * pickCont = [[UIImagePickerController alloc] init]; pickCont.delegate = imgPickerDelegate; pickCont.allowsImageEditing = YES; pickCont.sourceType = UIImagePickerControllerSourceTypeCamera; [self presentModalViewController:pickCont animated:YES]; } } @end   Codice  12:  A  sinistra:  interfaccia  e  implementazione  di  CameraViewController.  A  destra:  interfaccia  e   implementazione  di  ImmaginePickerControllerDelegate   4.1.1.2.1.1.2 Interfaccia  Grafica   La   costruzione   della   grafica   durante   la   progettazione   del   controller   dovrebbe   essere   eseguita   in   parallelo   con   la   scrittura   del   codice   perché   l’Xcode   e   l’Interface   Builder   lavorano   strettamente   in   cooperazione   tra   loro.   Nella   creazione   di   quest’interfaccia,   si   sono   impostati   gli   elementi   grafici   e   i   collegamenti  necessari  con  il  codice  tramite  l’”Inspector”.   Alcune   parti   dell’interfaccia,   comunque   sono   state   create   da   codice,   come   ad   esempio,   la   configurazione   del   navigation   bar   con   l’inserimento   al   suo   interno   dei   pulsanti   per   il   salvataggio   e   l’annullamento   di   azioni   invocate   dall’utente,   oppure   dello   spazio   dedicato   alla   visualizzazione   della     4-­‐55  
  • 56.
    foto   situato   graficamente   vicino   al   pulsante   “Scegli   foto”,   che   viene   stabilito,   nelle   sue   dimensioni,   attraverso  il  codice.       Figura  15:  Composizione  dell'interfaccia  di  AddViewController   4.1.1.2.1.2 PhotoDetailViewController   E’  il  controller  delegato  alla  visualizzazione  dei  dettagli  di  ciascun  punto  d’interesse.   Questa   maschera   sarà   richiamata   quando   l’utente,   posizionato   sulla   form   “RootViewController”,   selezionerà   un   determinato   record   e   conseguentemente   al   suo   tocco,   il   codice   della   “RootViewController”  richiamerà  le  informazioni  utili  riguardanti  quella  determinata  riga  e  caricherà  i   dati,  passando  attraverso  un’istanza  dell’oggetto  “Photo”.   Il   controller,   dovendo   quindi   visualizzare   i   dati   riguardanti   le   immagini,   dovrà   implementare   al   suo   interno  l’UIImagePickerControllerDelegate  che  permetterà  di  caricare  la  foto  corrispondente  al  punto.   4.1.1.2.1.2.1 Funzionamento   Questo  controller  deriva  dalla  classe  UITableViewController  che  permetterà  di  visualizzare  i  dati  sotto   forma   di   tabelle   grafiche   e   implementerà   dei   metodi   propri   per   stabilire   la   loro   rappresentazione   grafica.   Il  tutto  parte  dal  RootViewController,  nel  momento  in  cui  l’utente  decide  di  visualizzare  i  dettagli  della   tabella  iniziale:  il  PhotoDetailViewController  è  inizializzato  e  gli  è  passata  come  parametro  un’istanza   dell’oggetto  “Photo”,  la  quale  funge  da  “wrapper”  per  i  dati  stessi  e  che  contiene  tutte  le  informazioni   di  cui  questa  form  necessita.     A   questo   punto   nell’impostazione   della   grafica,   l’istanza   della   classe   “Photo”   è   scomposta   nelle   sue   proprietà   e   gli   appositi   campi   delle   tabelle   in   essa   contenute   vengono   riempiti   con   le   informazioni   passate  dal  RootViewController.   #import <UIKit/UIKit.h> @class Photo; @interface PhotoDetailViewController : UITableViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>{ Photo *photo;   4-­‐56  
  • 57.
    UIButton *photoButton; } @property (nonatomic,retain) Photo *photo; @property (nonatomic, retain) IBOutlet UIButton *photoButton; - (IBAction)photoButtonPressed; - (void)updatePhotoButton; @end   #import "PhotoDetailViewController.h" #import "EditingPhotoViewController.h" #import "PhotoViewController.h" #import "Photo.h" @implementation PhotoDetailViewController @synthesize photoButton, photo; #pragma mark - #pragma mark LifeCycle // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.rightBarButtonItem = self.editButtonItem; UIBarButtonItem *cancelButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; self.navigationItem.leftBarButtonItem = cancelButton; [cancelButton release]; self.tableView.allowsSelectionDuringEditing = YES; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } - (void)viewDidUnload { }   4-­‐57  
  • 58.
    - (void)dealloc { [photo release]; [photoButton release]; [super dealloc]; } -(void)cancel{ [self.navigationController popViewControllerAnimated:YES]; } #pragma mark - #pragma mark tableView - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.title = photo.namePhoto; [photoButton setImage:photo.photoThumbnailImage forState:UIControlStateNormal]; [self updatePhotoButton]; [self.tableView reloadData]; } - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [super setEditing:editing animated:animated]; [self updatePhotoButton]; } #pragma mark Table view methods - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } // Customize the number of rows in the table view. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 2; } // 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) {   4-­‐58  
  • 59.
    cell = [[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease]; cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator; } // Set up the cell switch (indexPath.row) { case 0: cell.textLabel.text = @"Nome:"; cell.detailTextLabel.text = photo.namePhoto; break; case 1: cell.textLabel.text = @"Coordinate:"; NSNumber *lat = photo.latitudePhoto; NSNumber *longit = photo.longitudePhoto; //visualizzazione coordinate nella tabella float latFloat = [lat floatValue]; float longitFloat = [longit floatValue]; NSString *latStr = [NSString stringWithFormat:@"%.2f ", latFloat]; NSString *longitStr =[NSString stringWithFormat:@"%.2f",longitFloat]; NSString *coordinateStr = [NSString stringWithFormat:@" %@ , %@ ",latStr, longitStr]; cell.detailTextLabel.text = coordinateStr; break; case 3: cell.textLabel.text = @"Descrizione:"; cell.detailTextLabel.text = photo.descriptionPhoto; break; default: break; } return cell; } -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (self.editing) { EditingPhotoViewController *editingview = [[EditingPhotoViewController alloc] initWithNibName:@"EditingPhotoViewController"bundle:[NSBundle mainBundle]];   4-­‐59  
  • 60.
    editingview.photo = photo; [self.navigationController pushViewController:editingview animated:YES]; [editingview release]; } else { [tableView deselectRowAtIndexPath:indexPath animated:YES]; } } - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { return UITableViewCellEditingStyleNone; } - (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath { return NO; } #pragma mark - #pragma mark Photo - (IBAction)photoButtonPressed { if (self.editing) { UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; imagePicker.delegate = self; [self presentModalViewController:imagePicker animated:YES]; [imagePicker release]; } else { PhotoViewController *photoView = [[PhotoViewController alloc] init]; photoView.photo = photo; [self.navigationController pushViewController:photoView animated:YES]; [photoView release]; } } - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo { NSManagedObject *oldImage = (NSManagedObject *)photo.photoPoint; if (oldImage != nil) { [photo.managedObjectContext deleteObject:oldImage]; } PhotoPoint *image = [NSEntityDescription insertNewObjectForEntityForName:@"PhotoPoint"inManagedObjectContext:photo.managed ObjectContext];   4-­‐60  
  • 61.
    photo.photoPoint = image; [image setValue:selectedImage forKey:@"photoPoint"]; CGSize size = selectedImage.size; CGFloat ratio = 0; if (size.width > size.height) { ratio = 128.0 / size.width; } else { ratio = 130.0 / size.height; } CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height); UIGraphicsBeginImageContext(rect.size); [selectedImage drawInRect:rect]; photo.photoThumbnailImage = UIGraphicsGetImageFromCurrentImageContext(); [self dismissModalViewControllerAnimated:YES]; } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [self dismissModalViewControllerAnimated:YES]; } - (void)updatePhotoButton { BOOL editing = self.editing; if (photo.photoThumbnailImage != nil) { photoButton.highlighted = editing; } else { photoButton.enabled = editing; } } @end   Codice  13:Interfaccia  e  implementazione  di  PhotoDetailViewController   4.1.1.2.1.2.2 Interfaccia  Grafica   La   grafica   è   organizzata,   come   già   scritto,   sotto   forma   di   più   campi   tabellari   che   elencano   i   dati   del   punto   e   di   un   elemento   di   tipo   UIView   dove   è   stato   posto   un   bottone   chiamato,   “Scegli   foto”   che   consente,   secondo   lo   stato   di   “editing”   in   cui   si   trova   il   controller,   di   associare   o   visualizzare   la   foto   presente  nella  libreria  di  quel  punto.   Nel   caso   della   visualizzazione   della   foto   associata,   verrà   inizializzato   un   altro   controller,   nominato   “PhotoViewController”,   mentre   nel   caso   in   cui   il   controller   risulti   essere   in   modalità   editing,   invece,   sarà  aperta  la  libreria  fotografica.           4-­‐61  
  • 62.
      Figura  16:  Rappresentazione  dell'interfaccia  grafica  di  PhotoDetailViewController   4.1.1.2.1.3 PhotoViewController   E’  la  form  delegata  a  rappresentare  l’immagine  che  descrive  un  punto  d’interesse.   Essa   è   invocata   dal   “PhotoDetailViewController”   il   quale   la   inizializzerà   e   le   assegnerà   un   determinato   valore  alla  proprietà  di  tipo  “Photo”.   Graficamente   sarà   composto   da   un   oggetto   grafico   UIImageView   che   sarà   impostato   attraverso   l’Interface  Builder  ma  la  cui  immagine  sarà  dimensionata  tramite  codice.       4.1.1.2.1.3.1 Funzionamento   Il   “PhotoViewController”   sarà   inizializzato   dal   PhotoDetailViewController   il   quale   come   scritto   imposterà  la  proprietà  di  tipo  “Photo”.   Da   quest’istanza   si   estrarranno   i   dati   per   la   visualizzazione   dell’immagine   e   il   nome   del   punto   che   servirà   ad   impostare   il   titolo   del   controller   visuale   e   si   setteranno   i   parametri   del   visualizzatore   d’immagine.   #import <UIKit/UIKit.h> @class Photo; @interface PhotoViewController : UIViewController { Photo *photo; UIImageView *imageView; }   4-­‐62  
  • 63.
    @property (nonatomic, retain)Photo *photo; @property (nonatomic, retain) UIImageView *imageView; @end   #import "PhotoViewController.h" #import "Photo.h" @implementation PhotoViewController @synthesize photo, imageView; #pragma mark - #pragma mark lifecycle - (void)viewDidLoad { [super viewDidLoad]; self.title = photo.namePhoto; UIBarButtonItem *cancelButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; self.navigationItem.leftBarButtonItem = cancelButton; [cancelButton release]; imageView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame]; imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; imageView.contentMode = UIViewContentModeScaleAspectFit; imageView.backgroundColor = [UIColor whiteColor]; self.view = imageView; imageView.image = [photo.photoPoint valueForKey:@"photoPoint"]; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; } - (void)viewDidUnload { } - (void)dealloc { [photo release]; [imageView release]; [super dealloc]; } #pragma mark - #pragma mark Button's methods -(void) cancel{ [self.navigationController popViewControllerAnimated:YES]; } @end   Codice  14:Interfaccia  e  implementazione  di  PhotoViewController     4-­‐63  
  • 64.
    4.1.1.2.1.4 EditingPhotoViewController   E’  il  view  controller  che  serve  a  modificare  le  informazioni  di  un  determinato  punto,  in  particolare  la   parte   delle   informazioni   inerenti   al   suo   nome   e   alla   sua   descrizione,   poiché   i   campi   riguardanti   le   coordinate  non  possono  essere  modificati  dall’utente.   4.1.1.2.1.4.1 Funzionamento   E’   una   classe   che   deriva   dall’UIViewController   e   gestisce   direttamente   gli   eventi   scatenati   dagli   oggetti   di   tipo   UITextField   e   UITextView   implementando   i   protocolli   UITextFieldDelegate   e   UITextViewDelegate.   Sostanzialmente   questo   controller   si   occuperà   della   sostituzione   dei   dati   già   presenti   nella   tabella,   dei   campi  riguardanti  il  nome,  descrizione  e  la  foto,  con  nuove  informazioni  compilate  dall’utente.   Il   codice   quindi   recupererà   il   contesto   dell’applicazione,   leggerà   i   campi   di   testo   e   assegnerà   i   loro   valori   a   un’istanza   della   classe   “Photo”,   aggiornando   poi   quel   determinato   record   della   tabella   con   l’invocazione  del  metodo  “save”.   #import <UIKit/UIKit.h> @class Photo; @interface EditingPhotoViewController : UIViewController<UITextFieldDelegate, UITextViewDelegate> { Photo *photo; UITextField *namePhotoTxt; UITextField *latitudePhotoTxt; UITextField *longitudePhotoTxt; UITextView *descriptionPhotoTxt; } @property (nonatomic,retain) Photo *photo; @property (nonatomic,retain) IBOutlet UITextField *namePhotoTxt; @property (nonatomic,retain) IBOutlet UITextField *latitudePhotoTxt; @property (nonatomic,retain) IBOutlet UITextField *longitudePhotoTxt; @property (nonatomic,retain) IBOutlet UITextView *descriptionPhotoTxt; @end   #import "EditingPhotoViewController.h" #import "Photo.h" @implementation EditingPhotoViewController @synthesize photo, namePhotoTxt, latitudePhotoTxt, longitudePhotoTxt, descriptionPhotoTxt; #pragma mark - #pragma mark Lifecycle // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad];   4-­‐64  
  • 65.
    self.title = @"Editingfoto"; UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; self.navigationItem.leftBarButtonItem = cancelButton; [cancelButton release]; UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@"Salva"style:UIBarButtonItemStyleDone target:self action:@selector(save)]; self.navigationItem.rightBarButtonItem = saveButton; [saveButton release]; self.namePhotoTxt.text = photo.namePhoto; NSNumber *lat = photo.latitudePhoto; NSNumber *longit = photo.longitudePhoto; //visualizzazione coordinate nei textField float latFloat = [lat floatValue]; float longitFloat = [longit floatValue]; NSString *latStr = [NSString stringWithFormat:@"%.2f ", latFloat]; NSString *longitStr =[NSString stringWithFormat:@"%.2f",longitFloat]; self.latitudePhotoTxt.text = latStr; self.longitudePhotoTxt.text = longitStr; self.descriptionPhotoTxt.text = photo.descriptionPhoto; } -(BOOL) textFieldShouldReturn:(UITextField *)textField{ [namePhotoTxt resignFirstResponder]; return YES; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; } - (void)viewDidUnload { } - (void)dealloc { [photo release]; [namePhotoTxt release]; [latitudePhotoTxt release]; [longitudePhotoTxt release]; [descriptionPhotoTxt release]; [super dealloc];   4-­‐65  
  • 66.
    } #pragma mark - #pragmamark Button's Method -(void)cancel{ [self.navigationController popViewControllerAnimated:YES]; } -(void)save{ float latitude = [latitudePhotoTxt.text floatValue]; float longitude = [longitudePhotoTxt.text floatValue]; NSNumber *latitudeNumber = [NSNumber numberWithFloat:latitude]; NSNumber *longitudeNumber = [NSNumber numberWithFloat:longitude]; //setup valori della classe Photo photo.namePhoto = namePhotoTxt.text; photo.latitudePhoto = latitudeNumber; photo.longitudePhoto = longitudeNumber; photo.descriptionPhoto = descriptionPhotoTxt.text; NSError *error = nil; if (![photo.managedObjectContext save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); exit(-1); // Fail } [self.navigationController popViewControllerAnimated:YES]; } @end   Codice  15:  Interfaccia  e  implementazione  di  EditingPhotoViewController   4.1.1.2.1.4.2 Interfaccia  Grafica   L’interfaccia   di   questo   controller   si   presenterà   composta   da   un   campo   di   testo   modificabile   che   rappresenterà  il  nome  del  punto  d’interesse,  seguito  poi  dalla  sua  descrizione,  anch’essa  modificabile  e   dai  campi  di  visualizzazione  delle  coordinate,  non  modificabili.     4-­‐66  
  • 67.
      Figura  17:  Interfaccia  grafica  dell'EditingPhotoViewController   4.1.1.2.1.5 RootViewController   Per  quanto  concerne  il  discorso  riguardante  questo  controller,  la  spiegazione  sul  suo  funzionamento   sarà   suddivisa   su   più   capitoli   poiché   è   la   base   di   tutto   il   funzionamento   del   progetto   e   quindi   incorporerà  in  parte  anche  le  funzionalità  degli  altri  moduli.   In   questo   paragrafo   si   tratterà   la   parte   del   view   controller   che   gestisce   le   tabelle   del   database   con   i   metodi   coinvolti   nel   caricamento   dei   dati   nell’interfaccia   grafica   e   nella   memoria   temporanea   necessaria  alle  successive  elaborazioni.     Esso   è   di   tipo   UITableViewController   poiché   le   informazioni   contenute   in   memoria,   saranno   rappresentate   con   una   grafica   simile   a   una   tabella   e   implementerà   il   protocollo   “NSFetchedResultsControllerDelegate”   che   faciliterà   il   caricamento   e   l’estrazione   dei   dati   stessi   dalla   memoria.   4.1.1.2.1.5.1 Funzionamento   Quando  è  caricata  la  maschera  “RootViewController”,  sono  inizializzati  sia  il  contesto  dell’applicazione   sia  gli  altri  parametri  necessari  all’iterazione  con  il  database  creato  inizialmente.   Bisogna   evidenziare   che   ogni   volta   che   ci   sarà   un’iterazione   con   i   dati   memorizzati   in   tabella,   sarà   inizializzata   e   usata   un’istanza   dell’oggetto   NSFetchedResultsController,   che   sarà   ottenuta   andando   dapprima  a  impostare  un  sort  descriptor  sulla  fetch  request.   Quando   in   sostanza   sarà   richiesto   il   caricamento   di   questa   form,   nel   metodo   “ViewDidLoad”   verrà   richiamato   il   metodo   fetchedResultsController   che   restituirà   un   oggetto   di   tipo   NSFetchedResultsController,  il  quale  invocherà  il  metodo  performFetch  che  ritornerà  una  prima  serie   di  dati  .   - (void)viewDidLoad {   4-­‐67  
  • 68.
    NSError *error; if (![[self fetchedResultsController] performFetch:&error]) { // Update to handle the error appropriately. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); exit(-1); // Fail } }   - (NSFetchedResultsController *)fetchedResultsController { if (fetchedResultsController != nil) { return fetchedResultsController; } /* Set up the fetched results controller. */ // Create the fetch request for the entity. NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; // Edit the entity name as appropriate. NSEntityDescription *entity = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:managedObjectContext]; [fetchRequest setEntity:entity]; // Set the batch size to a suitable number. [fetchRequest setFetchBatchSize:20]; // Edit the sort key as appropriate. NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"namePhoto" ascending:NO]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; [fetchRequest setSortDescriptors:sortDescriptors]; // Edit the section name key path and cache name if appropriate. // nil for section name key path means "no sections". NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"]; aFetchedResultsController.delegate = self; self.fetchedResultsController = aFetchedResultsController; [aFetchedResultsController release]; [fetchRequest release]; [sortDescriptor release]; [sortDescriptors release]; return fetchedResultsController; }   4-­‐68  
  • 69.
        A   questo   punto   saranno   richiamati   per   l’aggiornamento,   i   metodi   numberOfRowsInSection   e   cellForRowAtIndexPath,  come  mostrato  nel  seguente  pezzo  di  codice.   - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section]; return [sectionInfo numberOfObjects]; }   - (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] autorelease]; } Photo *photo = [fetchedResultsController objectAtIndexPath:indexPath]; TagPoint *tag = [[TagPoint alloc]init]; cell.textLabel.text = photo.namePhoto; if ((photo.namePhoto)!=nil) { [memory addObject: photo];//photo.namePhoto [tag setNamePoint:photo.namePhoto]; [tag setDescriptPoint:photo.descriptionPhoto]; [tag setLatPoint:photo.latitudePhoto]; [tag setLongitPoint:photo.longitudePhoto]; [memoryTag addObject:tag]; } } return cell; }     Quest’ultimo  metodo  configurerà  ogni  cella  della  table  view,  creerà  un’istanza  della  classe  Photo  e  la   assocerà   al   corrispettivo   fetchedResultsController   cosicché   si   estrarrà   dall’istanza   appena   creata   le   proprietà   che   si   vorranno   visualizzare   nella   schermata   (in   questo   caso   il   nome   del   punto)   e   si   assegneranno  i  valori  alle  altre  proprietà  dell’oggetto  “Photo”;  aggiungendo  alla  fine  del  metodo  ogni   istanza  della  classe  “Photo”  ad  un  array  per  la  memorizzazione  globale  dei  singoli  punti.     4-­‐69  
  • 70.
    Un  utente,  quindi,  dall’elenco  iniziale,  potrà  vedere  in  dettaglio  un  record  ben  preciso  grazie  al  metodo   didSelectRowAtIndexPath   che   permetterà   di   estrarre   tramite   il   fetchedResultsController   e   l’invocazione   del   metodo   objectatindexpath,   un   oggetto   del   tipo   “Photo”   il   cui   valore   imposterà   la   proprietà   di   tipo   “Photo”   della   classe   PhotoDetailViewController   che   servirà   a   visualizzare   i   dati   relativi  a  quel  determinato  record.   - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here -- for example, create and push another view controller. PhotoDetailViewController *photoDetailView = [[PhotoDetailViewController alloc] initWithNibName:@"PhotoDetailViewController"bundle:[NSBundle mainBundle]]; Photo *photo = (Photo *)[fetchedResultsController objectAtIndexPath:indexPath]; photoDetailView.photo = photo; //NSLog(@"sono in didSelectRowAtIndexPath..."); [self.navigationController pushViewController:photoDetailView animated:YES]; memoryTag = [[NSMutableArray alloc]init]; memory =[[NSMutableArray alloc]init]; POIs = [[NSMutableArray alloc]init]; [self.tableView reloadData]; }     Se   le   informazioni   saranno   cambiate,   ad   esempio   quando   l’utente   aggiungerà   dei   punti,   oppure   li   toglierà,  allora  sarà  invocato  il  metodo  “controllerDidChangeContent”  che  aggiornerà  la  table  view.   - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { // In the simplest, most efficient, case, reload the table view. [self.tableView reloadData]; }     Se  invece  la  vista  della  tabella  sarà  impostata  in  modalità  di  “editing”,  si  darà  la  possibilità  all’utente  di   modificare   i   record   esistenti,   eliminandone   quelli   scelti:   se   ciò   accadrà,   quindi,   significherà   che   sarà   stato  invocato  il  metodo  “commitEditingStyle”.     Esso  recupererà  il  contesto  attraverso  il  “fetchedResultsController”    che  poi  in  un  secondo  momento,   tramite   il   metodo   “deleteObject”   contenuto   in   esso,   permetterà   di   cancellare   dal   database   quel   determinato   dato,   salvando   poi   il   contesto   ad   azione   terminata   e   re-­‐invocando   il   metodo   viewDidLoad   per  l’aggiornamento  dell’interfaccia  grafica.     - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete the managed object for the given index path NSManagedObjectContext *context = [fetchedResultsController   4-­‐70  
  • 71.
    managedObjectContext]; [context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]]; // Save the context. NSError *error = nil; if (![context save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } [self viewDidLoad]; } }     4.1.2 Implementazione  dell’Augmented  Reality  (ARKit)   La   base   di   questo   sistema   è   la   libreria   rilasciata   dall’iPhoneDevCamp,   l’ARKit,   che   ha   permesso   lo   sviluppo   di   molteplici   applicativi   per   l’uso   della   realtà   aumentata,   come   ad   esempio   i   famosi   “Layar”   e   “Wikitude”.   Questa   libreria   è   stata   usata   su   molti   applicativi   di   questo   tipo   perché   fornisce   un   utilizzo   intuitivo,   almeno   per   quanto   concerne   lo   sviluppo   di   moduli   di   applicazioni   elementari   e   consente   allo   stesso   tempo  un  continuo  miglioramento  del  codice  da  parte  di  programmatori  esterni  al  gruppo  di  sviluppo,   grazie  alla  disponibilità  del  suo  codice.   Per   iniziare   a   capire   il   funzionamento   è   necessario   seguire   le   poche   indicazioni   disponibili   sulla   sua   struttura   logica   e   sul   modo   di   interagire   con   l’interfaccia   grafica,   poi,   il   programmatore   avrà   la   possibilità  di  ottenere  un  sistema  estremamente  dinamico  nel  suo  funzionamento.   Per  realizzare  questa  parte  del  progetto,  si  potevano  seguire  due  strade:   ⇒ Implementare  ARKit     ⇒ Sfruttare  le  API  di  Wikitude   La   soluzione   scelta,   è   stata   quella   di   usare   la   libreria   ARKit,   ovvero   la   madre   delle   API   di   Wikitude,   perché  presentava,  rispetto  alla  seconda  scelta,    meno  vincoli  per  lo  sviluppo  di  un  programma.     La   caratteristica   fondamentale   di   questa   libreria   è   la   suddivisione   del   suo   funzionamento   in   due   moduli  distinti  :   • Il  primo  usato  per  l’elaborazione  dei  punti  d’interesse  presi  in  ingresso  dal  sistema;   • Il   secondo   sviluppato   per   l’analisi   automatica   dei   dati   (compresa   l’iterazione   fra   i   sensori   del   telefono  e  i  punti  d’interesse).         4-­‐71  
  • 72.
      Figura  18:  Schema  a  blocchi  del  funzionamento  dell'implementazione  dell'ARKit   4.1.2.1 Funzionamento  dell’ARKit   Per  semplificare  la  spiegazione,  si  partirà  con  la  trattazione  generica  sul  come  sono  caricati  i  dati  da   elaborare.   In   linea   generica,   i   punti   per   essere   disponibili,   dovranno   essere   memorizzati   in   un   array  che   conterrà   un’istanza   dell’oggetto   “ARGeoCoordinate”   il   quale   verrà   inizializzato   con   un   oggetto   del   tipo   CLLocation.     L’istanza  di  questa  classe,  invece  sarà  inizializzata  tramite  i  seguenti  metodi:   • initWithCoordinate:   • altitude:   • horizontalAccuracy:   • verticalAccuracy:   •  timestamp:   Il   primo   accetterà   i   dati   contenuti   in   una   “structure”   chiamata   “CLLocationCoordinate2D”   che   memorizzerà   la   latitudine   e   la   longitudine,   espresse   nel   sistema   WGS84;   mentre   gli   altri   metodi   serviranno   a   impostare   i   valori   di   altitudine,   accuratezza   delle   misure   piane   e   verticali   e   il   periodo   temporale  di  misura.   Il   riempimento   dell’array   con   i   dati   voluti,   sarà   eseguito   tramite   un   metodo   inserito   nel   RootViewController   chiamato   “completeArrayOfPOI”   che   restituirà   l’array   con   gli   elementi   memorizzati.   Quest’ultimo  sarà  invocato  quando  l’utente  richiamerà  la  visualizzazione  dei  punti  d’interesse,  tramite   la   libreria   dell’Augmented   Reality   nel   metodo   “viewArController”.   Quando   tutti   i   punti   della   tabella   saranno  memorizzati  nell’array,  sarà  inizializzato  il  controller  ARGeoViewController  assieme  alle  sue   proprietà  che  saranno  impostate  con  valori  adeguati.  Per  poterlo  utilizzare,  la  classe  che  lo  invocherà,   dovrà  implementare  il  protocollo  ”ARViewDelegate”,  impostando  la  sua  proprietà  di  ”delegate”.   - (NSMutableArray *)completeArrayOfPOI { NSMutableArray *temp = [[NSMutableArray alloc]init]; CLLocation *tempLocation; ARGeoCoordinate *tempCoordinate; CLLocationCoordinate2D location; NSEnumerator *enumerator = [memory objectEnumerator]; id obj; while ( obj = [enumerator nextObject] ) { Photo *p= [[Photo alloc]init];   4-­‐72  
  • 73.
    p = obj; NSString *name = p.namePhoto; NSNumber *lat = p.latitudePhoto; NSNumber *longit = p.longitudePhoto; float latFloat = [lat floatValue]; float longitFloat = [longit floatValue]; location.latitude = latFloat; location.longitude = longitFloat; tempLocation = [[CLLocation alloc] initWithCoordinate:location altitude:100.0 horizontalAccuracy:1.0 verticalAccuracy:1.0 timestamp:[NSDate date]]; tempCoordinate = [ARGeoCoordinate coordinateWithLocation:tempLocation]; tempCoordinate.title = name; [temp addObject:tempCoordinate]; [tempLocation release]; } return temp; } -(void) viewArController{ self.locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; BOOL headingAvailable = [locationManager headingAvailable]; if (headingAvailable==NO) { UIAlertView * erroreAlert = [[UIAlertView alloc]initWithTitle:@"Errore nella bussola " message:@"Bussola non supportata!L'applicazione terminerà." delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [erroreAlert show]; [erroreAlert release]; exit(1); } ARGeoViewController *viewController = [[ARGeoViewController alloc] init]; viewController.debugMode = NO;//YES; viewController.delegate = self; viewController.scaleViewsBasedOnDistance = YES; viewController.minimumScaleFactor = .5; viewController.rotateViewsBasedOnPerspective = YES; [viewController addCoordinates:[self completeArrayOfPOI]];   4-­‐73  
  • 74.
    viewController.centerLocation = newCenter; [viewController startListening]; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: viewController]; [self.navigationController presentModalViewController:navController animated:YES]; [viewController release]; } Codice  16:  I  metodi  completeArrayOfPOI  e  viewArController   Il   protocollo   quindi   obbligherà   in   sostanza   una   determinata   classe   a   definire   il   metodo   “viewForCoordinate”   che   restituirà   un   oggetto   di   tipo   UIView   che   sarà   utilizzato   nella   rappresentazione  grafica  dei  punti  memorizzati.   Quest’ultimo  metodo  come  si  vede  dal  codice,  accetterà  in  ingresso  un  oggetto  di  tipo  “ARCoordinate”   che  conterrà  i  campi,  non  obbligatori,  del  nome  e  di  una  possibile  descrizione  del  punto  inserito  e  al   suo  interno  costruirà  in  maniera  precisa  ogni  rappresentazione  grafica  dei  punti  d’interesse,  andando   a   definire   l’area   di   visualizzazione   delle   informazioni   dei   POI   e   creando   tramite   codice   gli   oggetti   di   tipo  UIView  che  serviranno  a  contenere  le  label  (etichette)  per  la  visualizzazione  del  nome  del  punto  e   l’immagine,  con  lo  scopo  di  dare  una  rappresentazione  grafica  dei  singoli  punti.   #define BOX_WIDTH 150 #define BOX_HEIGHT 100 //visualizzazione delle informazioni relative a un punto - (UIView *)viewForCoordinate:(ARCoordinate *)coordinate { CGRect theFrame = CGRectMake(0, 0, BOX_WIDTH, BOX_HEIGHT); UIView *tempView = [[UIView alloc] initWithFrame:theFrame]; UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, BOX_WIDTH, 20.0)]; titleLabel.backgroundColor = [UIColor colorWithWhite:.3 alpha:.8]; titleLabel.textColor = [UIColor whiteColor]; titleLabel.textAlignment = UITextAlignmentCenter; titleLabel.text = coordinate.title; //titleLabel.text = coordinate.subtitle; [titleLabel sizeToFit]; titleLabel.frame = CGRectMake(BOX_WIDTH / 2.0 - titleLabel.frame.size.width / 2.0 - 4.0, 0, titleLabel.frame.size.width + 8.0, titleLabel.frame.size.height + 8.0); UIImageView *pointView = [[UIImageView alloc] initWithFrame:CGRectZero]; pointView.image = [UIImage imageNamed:@"location.png"]; pointView.frame = CGRectMake((int)(BOX_WIDTH / 2.0 - pointView.image.size.width / 2.0), (int)(BOX_HEIGHT / 2.0 - pointView.image.size.height / 2.0), pointView.image.size.width, pointView.image.size.height);   4-­‐74  
  • 75.
    [tempView addSubview:titleLabel]; [tempView addSubview:pointView]; [titleLabel release]; [pointView release]; return [tempView autorelease]; }   Codice  17:  Il  metodo  viewForCoordinate     4.1.2.1.1 Interfaccia  Grafica   Per  questo  modulo  del  progetto  la  parte  grafica  è  stata  impostata  completamente  da  codice,  partendo   dal   pulsante   situato   sulla   toolbar   nel   RootViewController,   nominato   “System   AR”,   che   consente   all’utente  di  richiamare  i  metodi  e  le  classi  necessari  alla  creazione  dell’Augmented  Reality.   Quando   il   programma   avrà   eseguito   la   calibrazione   del   ricevitore   GPS   e   impostato   le   coordinate   dell’utente   definite   come   il   punto   di   riferimento   del   sistema,   aprirà   l’ARGeoViewController   e   inizializzerà   e   imposterà   la   schermata   che   gestirà   la   fotocamera   visualizzando   i   punti   d’interesse,   muovendoli  sullo  schermo  ad  ogni  cambiamento  di  posizione  del  dispositivo.   4.1.3 L’utilizzo  dei  web  services  nell’applicazione   Lo  sviluppo  di  questa  parte  del  programma  ha  lo  scopo  di  farlo  iterare  con  i  servizi  già  disponibili  in   rete   per   il   caricamento   in   memoria   di   nuovi   dati   corrispondenti   a   punti   d’interesse   specificati   in   database   remoti   e   sono   resi   disponibili   a   qualsiasi   sviluppatore   con   o   senza   la   registrazione   del   programma  che  li  utilizzerà.     Uno  dei  problemi  di  questi  servizi,  è  quello  che  nella  maggior  parte  dei  casi  essi  non  coprono  con  i  loro   dati   l’Italia   e   l’Europa   ma   solamente   l’America   e   l’Australia,   quindi,   per   testare   il   programma,   si   è   dovuto  selezionare  un  insieme  di  servizi  web  che  coprisse  anche  il  nostro  stato.  Probabilmente  il  tutto   è  causato,  dal  fatto  che  questi  ultimi  sono  stati  implementati  prima  in  America,  in  quanto  in  Europa  si  è   avuta  una  diffusione  della  rete  per  un  uso  pubblico,  anche  sui  dispositivi  mobili,  solamente  negli  ultimi   anni.   Per   decidere   quale   web   service   utilizzare,   si   sono   analizzati   quelli   che   potevano   soddisfare   le   specifiche  del  progetto,  ovvero  che  fornissero  notizie  su  punti  d’interesse  come  attività  commerciali  o   musei   e   località   vicine   all’utente;   poi   si   sono   lette   le   documentazioni     riguardanti   la   loro   implementazione,   ossia   la   struttura   della   richiesta   da   inviare   e   della   risposta   mandata,   con   lo   scopo   di   rendere  il  programma  capace  di  inviare  e  ricevere  i  dati  richiesti  utilizzandoli  per  i  suoi  scopi.   I   web   services   presi   in   considerazione   sono   stati   quelli   che,   in   base   alle   coordinate   espresse   in   latitudine   e   longitudine   restituivano   i   POI   vicini   all’utente,   con   annesse   le   informazioni   ad   esempio   sul   nome   del   luogo,   sulla   sua   storia,   o   trattando   dati   di   locali   commerciali,   il   loro   nome,   le   informazioni   utili  sulla  loro  attività.     Quelli  in  esame  sono  alla  fine  risultati  essere  un  ristretto  numero,  tra  i  quali:   • Yahoo  Search  Service  per  la  ricerca  di  attività  commerciali     • Geonames.org  per  i  punti  d’interesse  riguardanti  località  turistiche   Il   primo   richiede   la   registrazione   gratuita   del   programma   fornendo   a   Yahoo   i   dati   dello   sviluppatore   e   il   nome   del   programma   sul   quale   implementare   il   servizio.   Eseguite   queste   operazioni,   il   gestore   fornisce   una   chiave   che   serve   al   sistema   per   l’identificazione   del   programma   che   ha   richiesto   le     4-­‐75  
  • 76.
    informazioni,  e  che  sarà  inserita  nella  cosiddetta  stringa  di  richiesta.  La  motivazione  per  la  quale,  dopo   svariate   prove,   non   è   stato   preso   in   considerazione   è   che   provandolo   con   le   coordinate   di   Trieste   e   Roma,  la  risposta  rimaneva  vuota  probabilmente  perché  per  l’Italia  non  ci  sono  dati  disponibili.     Allora   si   è   deciso   d’implementare   uno   dei   web   services   disponibili   sul   server   di   geonames.org   e   in   particolare   quello   chiamato   “findNearByWikipedia”   che   utilizza   come   parametri   in   ingresso   le   coordinate   di   un   punto   espresse   in   latitudine   e   longitudine   e   restituisce   un   documento   in   formato   xml   che  contiene  le  informazioni  richieste.   4.1.3.1 Funzionamento   Le   operazioni   per   l’estrazione   delle   informazioni   dei   punti   d’interesse   dal   web   service   sono   relegate   alla  classe  NSXmlParser  che  si  occupa  del  parsing  del  messaggio  xml   prelevando  i  dati  utili  dai  tag  del   messaggio.   In   questo   progetto   si   richiede   l’esecuzione   di   queste   operazioni   due   volte:   durante   l’aperturai   della   mappa   dove   si   localizzano   i   pin   dei   punti   d’interesse   inseriti   dall’utente   e   quelli   caricati   tramite   il   web   service  e  quando  l’utente  richiede  la  form  in  cui  è  implementata  l’Augmented  Reality.   Prima  di  iniziare  a  parlare  del  modo  in  cui  opera  il  metodo  “viewMap”  delegato  al  caricamento  dei  dati   e  alla  visualizzazione  della  mappa,  è  necessario  sapere  com’è  costituito  il  sistema.   4.1.3.1.1 Struttura  della  request  e  del  messaggio  di  response  del  web  service   Per   riuscire   a   interagire   con   il   web   service   scelto,   si   è   dovuto   leggere   la   parte   descrittiva   del   documento   riguardante   il   servizio   scelto   all’indirizzo   http://www.geonames.org/export/web-­ services.html   dove   è   esposta   una   breve   rappresentazione   della   funzionalità   dei   servizi   disponibili,   come   ad   esempio   i   parametri   accettati   nella   stringa   di   “request”   e   gli   elementi   ritornati   nella   “response”.     Figura  19:  Descrizione  del  web  service   Per   capire   com’è   composta   la   response,   si   dovrà   cliccare   sull’esempio   di   richiesta   e   così   facendo   comparirà  in  risposta  un  documento  visualizzato  nel  browser  in  formato  xml,  che  sarà  costituito,  come   scritto  in  precedenza  da  svariati  “tag”  ciascuno  dei  quali  descriverà  un  particolare  elemento.     4-­‐76  
  • 77.
      Figura  20:  documento  xml  restituito  dal  web  service     4.1.3.1.2 Comunicazione  fra  i  controller   Per   permettere   il   passaggio   di   parametri   tra   il   controller   principale   e   quello   delegato   alla   visualizzazione  dei  punti  sulla  mappa,  si  sono  costruite  due  classi,  chiamate  rispettivamente  TagPoint   e  POIStore.   La  prima  fornisce  l’identificazione  di  ciascun  punto  d’interesse,  in  altre  parole,  quando  si  dovrà  parlare   dei   singoli   punti,   si   dovrà   considerare   un’istanza   della   classe   “TagPoint”   che   conterrà   al   suo   interno   la   descrizione  intera  dell’oggetto  contenendo  le  proprietà  relative  al  suo  nome,  alla  sua  descrizione,  alle   sua  latitudine  e  longitudine.     Mentre   per   quanto   riguarda   la   seconda   classe,   essa   avrà   il   compito   di   inizializzare   e   contenere   in   definita  l’array  che  servirà  a  memorizzare  l’insieme  d’istanze  di  oggetti  di  tipo  “TagPoint”  e  che  verrà   poi   utilizzata   per   l’estrazione   dei   singoli   punti   dal   controller   chiamato   “TagViewController”,   di   cui   si   esaminerà  il  funzionamento  nei  capitoli  successivi.     Figura  21:  Passaggio  di  parametri  tra  i  due  view  controller     4-­‐77  
  • 78.
    #import <Foundation/Foundation.h> #import "TagPoint.h" @interface TagPoint : NSObject { @implementation TagPoint @private NSString *namePoint; @synthesize namePoint, descriptPoint, @private NSString *descriptPoint; urlWiki, latPoint, longitPoint; @private NSNumber *latPoint; -(id)init @private NSNumber *longitPoint; { namePoint = [[NSString alloc] init]; descriptPoint =[[NSString alloc]init]; } latPoint = [[NSNumber alloc] init]; longitPoint = [[NSNumber alloc] init]; @property (nonatomic,retain) NSString return self; *namePoint; } @property (nonatomic,retain) NSString -(void) setLatPoint:(NSNumber *)lat *descriptPoint; { @property (nonatomic,retain) NSNumber latPoint = lat; *latPoint; } @property (nonatomic,retain) NSNumber -(void) setLongitPoint:(NSNumber *)longit *longitPoint; { longitPoint = longit; -(id)init; } -(void) setLatPoint:(NSNumber *)lat; -(void) setNamePoint:(NSString *) name -(void) setLongitPoint:(NSNumber *)longit; { -(void) setNamePoint:(NSString *) name; namePoint = name; -(void) setDescriptionPoint:(NSString } *)descript; -(void) setDescriptionPoint:(NSString -(NSString *) getNamePoint; *)descript -(NSString *) getDescriptionPoint; { -(NSNumber *) getLatPoint; descriptPoint = descript; -(NSNumber *) getLongitPoint; } -(NSString *) getNamePoint @end   { return namePoint; } -(NSString *) getDescriptionPoint { return descriptPoint; } -(NSNumber *) getLatPoint { return latPoint; } -(NSNumber *) getLongitPoint { return longitPoint; } @end     4-­‐78  
  • 79.
    #import <Foundation/Foundation.h> #import "POIStore.h" #import "TagPoint.h" @class TagPoint; @interface POIStore: NSObject { @implementation POIStore @private NSMutableArray *photos; } @synthesize photos; @property(nonatomic, retain) NSMutableArray *photos; - (id) init - (id) init; { - (void) setPOI:(NSMutableArray *)array; self = [super init]; - (NSMutableArray *)getPOI; photos = [[NSMutableArray alloc]init]; @end   return self; } - (NSMutableArray *) getPOI { return photos; } -(void)setPOI: (NSMutableArray *)array { photos = array; } - (void) dealloc { [photos release]; [super dealloc]; } @end   Codice  18:  Interfacce  e  implementazioni  delle  classi  TagPoint  e  POIStore   Quando  poi,  saranno  passati  questi  parametri  al  TagViewController,  ossia  il  controller  incaricato  alla   visualizzazione   della   mappa,   sarà   eseguito   il   procedimento   inverso,   ovvero   la   classe   estrarrà   dall’istanza  dell’oggetto  “POIStore”  l’array  delle  istanze  di  “TagPoint”  che  conterranno  le  informazioni   relative  ad  ogni  singolo  punto.     Per   quanto   concerne   il   secondo   uso   di   questi   dati,   ovvero   quando   l’utente   invocherà   la   realtà   aumentata,  si  eseguirà  lo  stesso  procedimento  spiegato  precedentemente  per  il  caricamento  dei  punti   sulla  mappa,  con  la  differenza  che  in  questo  caso  i  dati  verranno  caricati  nell’ARGeoViewController.     4.1.3.2 Visualizzazione  e  distribuzione  dei  punti  d’interesse  su  una  mappa     In  questo  capitolo  si  tratterà  il  discorso  della  visualizzazione  di  una  mappa  con  la  distribuzione,  su  di   essa,  dei  punti  d’interesse.   I  dati,  come  nel  precedente  caso,  una  volta  individuati  sono  memorizzati  in  un  array  che  servirà  a  far   passare  le  informazioni  da  un  controller  all’altro.   I   dati   memorizzati   quindi   serviranno   sia   a   localizzare   i   punti   sulla   mappa,   attraverso   la   latitudine   e   longitudine,  identificandoli  tramite  un  pin,  sia  a  contenere  le  informazioni  necessarie  a  descriverli.     4-­‐79  
  • 80.
    Sostanzialmente   ogni   qualvolta   l’utente   invocherà   la   sua   visualizzazione,   esso   caricherà   la   mappa   e   inizializzerà  l’array  con  i  punti  disponibili  nella  memoria  locale  e  con  quelli  scaricati  dal  web  service.     4.1.3.2.1 Funzionamento   Il   controller   che   è   richiamato   dal   “RootViewController”   per   la   visualizzazione   della   mappa   è   il   “TagViewController”  che  controlla  direttamente  la  mappa  attraverso  l’implementazione  del  protocollo   “MKMapViewDelegate”  e  l’inclusione  nella  classe  del  frame  work  MapKit.   In   esso   sono   inserite   le   proprietà   per   la   memorizzazione   dell’array   dei   punti,   l’oggetto   grafico   per   caricare  la  mappa  e  due  classi  chiamate  “TouchView”  e  “MoreInfoView”  derivanti  dalla  classe  UIView   per  la  visualizzazione  dei  punti  nella  mappa.   Il  sistema  quindi  sarà  così  composto:   ⇒ Dal  controller  principale  TagViewController;   ⇒ Dalla  classe  MyAnnotation;   ⇒ Dalle  due  classi  MoreInfoView  e  TouchView.   Il   primo   è   quello   che   gestisce   tutto   il   sistema  di  visualizzazione  della  mappa  e  coordina  le  classi   che   saranno   descritte   in   seguito,   caricando   i   dati   dei   punti   d’interesse,   inizializzando   le   classi   per   la   visualizzazione  della  mappa  e  quelle  delegate  all’iterazione  con  l’interfaccia  grafica:   ⇒ La  classe  TouchView  servirà  a  capire  se  l’utente  invocherà  un  evento  derivato  dalla  pressione   di  un  pulsante  oppure  no;   ⇒ La   classe   MoreInfoView   sarà   invocata   quando   il   programma   caricherà   la   form   per   la   visualizzazione  delle  informazioni  riguardanti  un  determinato  punto.   Oltre   a   impostare   queste   classi,   descriverà   dei   metodi   per   la   gestione   degli   eventi   riguardanti   l’apertura   e   la   chiusura   della   vista   gestita   dall’istanza   della   classe   MoreInfoView,   chiamati   “showAnnotation”   per   la   visualizzazione   delle   informazioni   del   singolo   punto   d’interesse   e   “hideAnnotation”  per  la  sua  chiusura.   Per   la   distribuzione   dei   “pin   ”   sulla   mappa,   nel   caricamento   della   form,   sarà   richiamato   il   metodo   appartenente   al   protocollo   MKMapViewDelegate,   “viewForAnnotation”,   per   un   numero   di   volte   pari   al   numero  dei  punti  d’interesse.   #import <UIKit/UIKit.h> #import <MapKit/MapKit.h> #import "TouchView.h" #import "MyAnnotation.h" #import "MoreInfoView.h" @class POIStore; @class TagPoint; @interface TagViewController : UIViewController<UINavigationControllerDelegate, MKMapViewDelegate> { //memorizzazione dati POIStore *poiStore; //array dei POI contenuti nell'oggetto POIStore NSMutableArray *arr; MKMapView *mapView; TouchView* touchView;   4-­‐80  
  • 81.
    IBOutlet MoreInfoView* moreInfoView; } @property(nonatomic,retain) POIStore *poiStore; @property(nonatomic, retain) NSMutableArray *arr; @property (nonatomic, retain) MKMapView* mapView; @property (nonatomic, retain) TouchView* touchView; @property (retain) IBOutlet MoreInfoView* moreInfoView; extern NSString *const GMAP_ANNOTATION_SELECTED; - (id) initWithPOIStore:(POIStore *) poiS; - (void) showAnnotation:(MyAnnotation*) annotation; - (void) hideAnnotation; @end #import "TagViewController.h" #import "POIStore.h"//wrapper dell'array creato #import "TagPoint.h" #import "CompactNavigatorAppDelegate.h" #import "MyAnnotationView.h" @implementation TagViewController @synthesize poiStore, arr; @synthesize mapView, touchView, moreInfoView; NSString * const GMAP_ANNOTATION_SELECTED = @"gmapselected"; #pragma mark - #pragma mark Lifecycle //inizializzazione del view controller - (id) initWithPOIStore:(POIStore *) poiS { self = [super init]; arr = [[NSMutableArray alloc]init]; arr = [poiS getPOI]; return self; } - (void)viewDidLoad { [super viewDidLoad]; UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self   4-­‐81  
  • 82.
    action:@selector(cancel)]; self.navigationItem.leftBarButtonItem = cancelButton; [cancelButton release]; touchView = [[TouchView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)]; touchView.delegate = self; touchView.callAtHitTest = @selector(stopFollowLocation); mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)]; mapView.delegate = self; [touchView addSubview:mapView]; [self.view addSubview:touchView]; NSMutableArray* annotations = [[NSMutableArray alloc] init]; NSEnumerator *enumerator = [arr objectEnumerator]; id obj; while ( obj = [enumerator nextObject] ) { TagPoint *tag = [[TagPoint alloc] init]; tag = obj; NSString *namePt = [[NSString alloc]init]; NSString *descrPt = [[NSString alloc] init]; NSString *linkPt = [[NSString alloc]init]; NSNumber *lat = tag.latPoint; NSNumber *longit = tag.longitPoint; namePt = [tag getNamePoint]; descrPt = [tag getDescriptionPoint];//modificato ora linkPt = [tag getURLWiki]; float latFloat = [lat floatValue]; float longitFloat = [longit floatValue]; CLLocationCoordinate2D coord2d = {latFloat,longitFloat}; MyAnnotation *anno = [[MyAnnotation alloc] initWithCoords:coord2d name:namePt descr:descrPt link:linkPt ]; [annotations addObject:anno]; [anno release]; } [mapView addAnnotations:annotations]; [annotations release]; self.moreInfoView.frame = CGRectMake(20.0, 250.0 + 300.0, self.moreInfoView.frame.size.width, self.moreInfoView.frame.size.height); [self.touchView addSubview:self.moreInfoView]; }   4-­‐82  
  • 83.
    #pragma mark - #pragmamark Map's method - (void) stopFollowLocation { MyAnnotation* annotation; for (annotation in mapView.selectedAnnotations) { [mapView deselectAnnotation:annotation animated:NO]; } [self hideAnnotation]; } - (void) annotationClicked: (id <MKAnnotation>) annotation { MyAnnotation* ann = (MyAnnotation*) annotation; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Map Tag View" message:[NSString stringWithFormat:@"You clicked at annotation: %@",ann.name] delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [alert show]; [alert release]; } - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { //NSLog(@"Sono qui...in mapView"); MKAnnotationView* annotationView = nil; MyAnnotation *myAnnotation = (MyAnnotation*) annotation; NSString* identifier = @"Pin"; MKPinAnnotationView* annView = (MKPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier]; if(nil == annView) { annView = [[[MKPinAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease]; } [annView addObserver:self forKeyPath:@"selected" options:NSKeyValueObservingOptionNew context:GMAP_ANNOTATION_SELECTED]; [annView setPinColor:MKPinAnnotationColorGreen]; CGPoint notNear = CGPointMake(10000.0,10000.0); annView.calloutOffset = notNear; annotationView = annView; [annotationView setEnabled:YES];   4-­‐83  
  • 84.
    [annotationView setCanShowCallout:YES]; return annotationView; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ NSString *action = (NSString*)context; if([action isEqualToString:GMAP_ANNOTATION_SELECTED]){ BOOL annotationAppeared = [[change valueForKey:@"new"] boolValue]; if (annotationAppeared) { [self showAnnotation:((MyAnnotationView*) object).annotation]; } else { [self hideAnnotation]; } } } - (void)showAnnotation:(MyAnnotation*)annotation { //configurazione dell'UITextView self.moreInfoView.descr.editable = NO;//disabilitazione dell'editing self.moreInfoView.descr.showsVerticalScrollIndicator = YES; self.moreInfoView.descr.font = [UIFont fontWithName:@"Arial" size:10]; self.moreInfoView.text.text = annotation.title; self.moreInfoView.descr.text = annotation.descr; NSRange range = NSMakeRange(self.moreInfoView.descr.text.length - 1, 1); [self.moreInfoView.descr scrollRangeToVisible:range]; [UIView beginAnimations: @"moveCNGCallout" context: nil]; [UIView setAnimationDelegate: self]; [UIView setAnimationDuration: 0.5]; [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut]; self.moreInfoView.frame = CGRectMake(10.0, 250.0, self.moreInfoView.frame.size.width, self.moreInfoView.frame.size.height); [UIView commitAnimations]; } - (void)hideAnnotation {   4-­‐84  
  • 85.
    self.moreInfoView.text.text = nil; [UIView beginAnimations: @"moveCNGCalloutOff" context: nil]; [UIView setAnimationDelegate: self]; [UIView setAnimationDuration: 0.5]; [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut]; self.moreInfoView.frame = CGRectMake(10.0, 250.0 + 300, self.moreInfoView.frame.size.width, self.moreInfoView.frame.size.height); [UIView commitAnimations]; } - (void)didReceiveMemoryWarning { NSLog(@"Attenzione sono con la memoria piena!"); [super didReceiveMemoryWarning]; } - (void)viewDidUnload { } - (void)dealloc { [poiStore release]; [mapView release]; [touchView release]; [moreInfoView release]; [super dealloc]; } #pragma mark - #pragma mark Button's Method -(void)cancel{ [self dismissModalViewControllerAnimated:YES]; } @end   Codice  19:  Interfaccia  e  implementazione  del  TagViewController   Per  la  visualizzazione  di  una  mappa,  il  frame  work  Mapkit  offre  la  possibilità  di  inserirci  al  suo  interno   dei  punti  chiamati  “pin”  per  l’identificazione  di  determinati  siti  d’interesse  per  mezzo  della  creazione   di  un’”annotazione”  che  è  composta  di  due  oggetti,  uno  di  tipo  “annotation”,  chiamato  MyAnnotation,    e   uno  di  tipo    “visual  annotazion”,  denominato  MoreInfoView.   La  classe  MyAnnotation  implementerà  il  protocollo  MKAnnotation  e  dovrà  contenere  le  informazioni   riguardanti   le   coordinate,   presenti   nella   proprietà   di   tipo   CLLocationCoordinate2D,   oltre   a   quelle   opzionali  di  tipo  NSString,  relative  al  nome  e  alla  descrizione  del  punto.     4-­‐85  
  • 86.
    In   aggiunta,   nella   costruzione   di   questa   classe,   è   stato   anche   implementato   un   metodo,   chiamato   “initWithCoordinate”,   con   lo   scopo   di   impostare   i   valori   delle   proprietà   al   momento   della   sua   inizializzazione.   #import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface MyAnnotation : NSObject<MKAnnotation> { CLLocationCoordinate2D coordinate; NSString *name; NSString *title; NSString *descr; } @property (nonatomic, readonly) CLLocationCoordinate2D coordinate; @property (nonatomic,retain) NSString *name; @property (nonatomic,retain) NSString *title; @property (nonatomic,retain) NSString *descr; - (id) initWithCoords:(CLLocationCoordinate2D) coords name:(NSString*) inputName descr:(NSString*) inputDescr link:(NSString*) inputLink ; @end   #import "MyAnnotation.h" @implementation MyAnnotation @synthesize coordinate, name, title, descr, link; - (id) initWithCoords:(CLLocationCoordinate2D) coords name:(NSString*) inputName descr:(NSString*)inputDescr link:(NSString*)inputLink { self = [super init]; if (self != nil) { coordinate = coords; self.name = inputName; self.title = inputName; self.descr = inputDescr; } return self; } @end       4-­‐86  
  • 87.
    L’”annotazione   visuale”   sarà   composta   dalle   classi   MoreInfoView   e   TouchView   che   serviranno   a   descrivere  le  informazioni  dettagliate  di  ciascun  punto  e  saranno  chiamate  quando  l’utente  cliccherà   su  un  determinato  “pin”  o  su  un  qualsiasi  punto  della  mappa.     #import <Foundation/Foundation.h> #import "MoreInfoView.h" @interface MoreInfoView : UIView { @implementation MoreInfoView IBOutlet UILabel* text;//nome @synthesize text; IBOutlet UITextView @synthesize descr; *descr;//descrizione POI @synthesize linkWiki; } @end   @property (nonatomic, retain) IBOutlet UILabel* text; @property (nonatomic, retain) IBOutlet UITextView *descr; @end #import <UIKit/UIKit.h> #import "TouchView.h" @class UIView; @interface TouchView () - (UIView *)hitTest:(CGPoint)point @interface TouchView : UIView { withEvent:(UIEvent *)event; id delegate; @end SEL callAtHitTest; @implementation TouchView } @synthesize delegate, callAtHitTest; @property (assign) id delegate; - (UIView *)hitTest:(CGPoint)point @property (assign) SEL callAtHitTest; withEvent:(UIEvent *)event { @end UIView* returnMe = [super   hitTest:point withEvent:event]; if (![returnMe isKindOfClass:[UIButton class]]) { [delegate performSelector:callAtHitTest]; } return returnMe; } @end   Codice  20:  Interfacce  e  implementazioni  -­  In  Alto:  MoreInfoView  -­  In  Basso:  TouchView   4.1.3.2.2 Interfaccia  Grafica   L’interfaccia   di   questa   parte   del   programma   è   stata   impostata   sia   tramite   codice,   come   si   è   visto   nel   paragrafo   precedente,   sia   tramite   l’Interface   Builder   dove   si   sono   impostati   i   campi   di   testo   per   l’oggetto   UIView   collegato   alla   classe   MoreInfoView   mentre   per   quanto   riguarda   il   controller   TagViewController   gli   elementi   grafici   sono   stati   inizializzati   tramite   l’Xcode   all’interno   dell’oggetto   grafico  UIView,  come  rappresentato  nella  figura  sottostante.     4-­‐87  
  • 88.
        Figura  22:  Interfaccia  grafica  del  TagViewController     4.1.4 Definizione  delle  funzioni  tipiche  dei  software  di  navigazione   Questo   capitolo   tratta   lo   sviluppo   del   modulo   che   include   le   tipiche   funzionalità   dei   software   di   navigazione,  come  stabilito  nelle  specifiche  precedentemente  fissate  all’elaborazione  del  progetto.   Per  prima  cosa,  si  è  deciso  di  creare  una  schermata  che  includesse  la  visualizzazione  di  una  mappa  e   poi   in   un   secondo   momento,   la   tracciatura   del   percorso   compiuto   dall’utente   in   un   determinato   intervallo  di  tempo,  fornendo  i  dati  della  sua  velocità  media  e  distanza  percorsa  a  processo  terminato.   Per   la   visualizzazione   della   mappa,   si   è   deciso   di   integrare   l’interfaccia   con   i   tre   tipi   di   rappresentazione,  disponibili  già  nelle  librerie  Mapkit:   ⇒ Standard(o  mappa)   ⇒ Satellite   ⇒ Hybrid  (un’associazione  fra  la  visualizzazione  ”Standard”  e  quella  dal  satellite)   Nel  sistema  in  questione,  grazie  al  collegamento  con  il  ricevitore  GPS,  si  ha  la  localizzazione  dell’utente   sulla   mappa   e   con   l’iterazione   del   magnetometro,   si   permette   la   sua   rotazione   verso   la   direzione   dell’utente,  facilitando  un  suo  rapido  orientamento.     4-­‐88  
  • 89.
      Figura  23:  Schema  di  funzionamento  del  modulo   4.1.4.1 Funzionamento   Questo  modulo  del  programma  è  costituito  da  due  view  controller:   1. TrackingViewController   2. TrackingView   Quando   l’utente   vuole   registrare   il   percorso,   invocherà   e   inizializzerà   dall’interfaccia   grafica   il   TrackingViewController.   Esso,  al  suo  caricamento,  si  collegherà  a  GoogleMaps  tramite  il  frame  work  Mapkit  e,  interagendo  con  il   ricevitore  GPS,  visualizzerà  con  un  pin,  la  sua  posizione  sulla  mappa.   4.1.4.1.1 TrackingViewController   4.1.4.1.1.1 Funzionamento   Questo   controller   avrà   il   compito   di   creare   l’iterazione   tra   il   controller   delegato   alla   visualizzazione   della  mappa,  ossia  il  TrackingView  e  le  periferiche  del  dispositivo,  quali  il  ricevitore  GPS  e  la  bussola   attraverso  i  seguenti  passaggi:   • Il   CLLocationManager   monitorerà   gli   aggiornamenti   della   posizione   dell’utente   e   dei   valori   della   bussola,   mandando   poi   dei   messaggi   al   view   controller   per   aggiornare   graficamente   l’inclinazione   della   mappa   con   l’utilizzo   della   classe   CLHeading   e   il   disegno   del   percorso   compiuto   dall’utente   sulla   mappa   tramite   l’uso   della   classe   CLLocation,   per   ricavare   le   coordinate  della  latitudine  e  longitudine  e  per  trovare  la  distanza  percorsa  dall’utente  ;   • Per   calcolare   il   tempo   impiegato   per   il   tragitto,   il   programma   necessiterà   anche   del   periodo   in   cui  si  è  iniziata  e  conclusa  la  misurazione,  con  l’utilizzo  della  classe  NSDate.   I  tre  metodi  sviluppati  per  lo  svolgimento  di  queste  operazioni  saranno  chiamati  rispettivamente:   1. selectMap:   2. toggleTracking:   3. resetMap:   Il   primo   sarà   quello   chiamato   per   la   modifica   della   visualizzazione   della   mappa   che   sarà   modificata   andando  ad  agire  sull’istanza  della  classe  MKMapView.     4-­‐89  
  • 90.
    Il   metodo   toggleTracking   sarà   richiamato   quando   l’utente   vorrà   stabilire   il   percorso   compiuto   in   un   determinato   tempo,   rilevando   a   fine   evento   la   velocità   media   tenuta   dalla   persona   e   la   distanza   percorsa.   Quest’ultimo   dato   sarà   fornito   direttamente   dalla   sommatoria   tra   i   risultati   della   funzione   della   libreria  chiamata  getDistanceFrom  che  opererà  sulla  differenza  fra  le  coordinate  del  punto  di  arrivo  e   quello  di  partenza,  mentre  il  tempo  sarà  ottenuto  dalla  differenza  fra  la  memorizzazione  del  periodo  di   fine  misurazione  e  quello  d’inizio.   Il  terzo  metodo  invece  servirà  a  cancellare  tutti  i  punti  finora  considerati  per  il  disegno  del  percorso   sulla  mappa.   La  manipolazione  della  mappa  sarà  delegata  alla  classe  derivata  UIView  che  consentirà  di  disegnare  su   di  essa  il  percorso  e  che  implementerà  i  metodi  per  la  gestione  della  classe  MKMapView.     #import <UIKit/UIKit.h> #import <MapKit/MapKit.h> #import <CoreLocation/CoreLocation.h> #import "TrackingView.h" @interface TrackingViewController : UIViewController<MKMapViewDelegate,CLLocationManagerDelegate> { IBOutlet MKMapView *mapView; TrackingView *trackingView; UIBarButtonItem *startButton; UIBarButtonItem *resetButton; UISegmentedControl *segmentTypeMap; //indice di selezione int selectedSegment; CLLocationManager *locationManager; CLHeading *heading; NSDate *startDate; float distance; BOOL tracking;//per vedere se è già in atto la traccia del percorso } @property (nonatomic, retain) MKMapView * mapView; @property (nonatomic, retain) TrackingView *trackingView; @property (nonatomic, retain) UIBarButtonItem *startButton; @property (nonatomic, retain) UIBarButtonItem *resetButton; @property (nonatomic, retain) UISegmentedControl *segmentTypeMap; @end   #import "TrackingViewController.h" @implementation TrackingViewController   4-­‐90  
  • 91.
    //Pulsanti @synthesize startButton, resetButton,segmentTypeMap;//bottoni per la partenza ed il reset del sistema //mappa @synthesize mapView, trackingView; #pragma mark - #pragma mark Lifecycle // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; tracking = NO; //NSLog(@"Sono in viewDidLoad"); } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } - (void)viewWillAppear:(BOOL)animated { NSLog(@"sono in viewWillAppear.."); tracking = NO; //pulsanti sul lato sx della toolbar // creo una toolbar che conterrà 2 pulsanti UIToolbar* tools = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 80, 44.01)]; // creo l'array che contiene i pulsanti, che saranno aggiunti alla toolba NSMutableArray* buttons = [[NSMutableArray alloc] initWithCapacity:2]; // creo il pulsante di start startButton = [[UIBarButtonItem alloc] initWithTitle:@"Start" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleTracking)]; [buttons addObject:startButton]; [startButton release]; // creo il reset resetButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(resetMap)]; //initWithTitle:@"Reset" style:UIBarButtonItemStyleBordered target:self   4-­‐91  
  • 92.
    action:@selector(resetMap)]; [buttons addObject:resetButton]; [resetButton release]; //fisso i bottoni nella toolbar [tools setItems:buttons animated:NO]; [buttons release]; // inserisco la toolbar nella nav bar self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:tools]; [tools release]; //pulsanti sulla destra del navigation bar //creo un array di stringhe per i pulsanti.. NSMutableArray *controls = [[NSMutableArray alloc] init]; [controls addObject:@"Map"]; [controls addObject:@"Satellite"]; [controls addObject:@"Hybrid"]; segmentTypeMap = [[UISegmentedControl alloc] initWithItems:controls]; [segmentTypeMap setSegmentedControlStyle:UISegmentedControlStyleBar]; [segmentTypeMap setMomentary:TRUE]; [segmentTypeMap addTarget:self action:@selector(selectMap:) forControlEvents:UIControlEventValueChanged]; selectedSegment = [segmentTypeMap selectedSegmentIndex]; UIBarButtonItem *segmentTypeBtn = [[UIBarButtonItem alloc] initWithCustomView:segmentTypeMap]; [segmentTypeMap release]; [self.navigationItem setRightBarButtonItem:segmentTypeBtn]; [segmentTypeBtn release]; // inizializzo TrackingView trackingView = [[TrackingView alloc] initWithFrame:mapView.frame]; // aggiungo trackingView come subview a mapView [mapView addSubview:trackingView]; [trackingView release]; // release di TrackingView // imposto come delegate di mapView, trackingView mapView.delegate = trackingView; // inizializzazione del location manager locationManager = [[CLLocationManager alloc] init]; // impostazione del delegate del locationManager locationManager.delegate = self;   4-­‐92  
  • 93.
    //set dell'accuratezza dellarappresentazione locationManager.desiredAccuracy = kCLLocationAccuracyBest; BOOL headingAvailable = [locationManager headingAvailable]; if (headingAvailable==NO) { UIAlertView * erroreAlert = [[UIAlertView alloc]initWithTitle:@"Errore nella bussola " message:@"Bussola non supportata!L'applicazione terminerà." delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [erroreAlert show]; [erroreAlert release]; exit(1); } [super viewWillAppear:animated]; } - (void)viewDidUnload { // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } - (void)dealloc { [startButton release]; [resetButton release]; [mapView release]; // release the mapView MKMapView [segmentTypeMap release]; [locationManager release]; [super dealloc]; } #pragma mark - #pragma mark Button's method - (void)toggleTracking { if (tracking) { tracking = NO; // stop tracking // l'iPhone può essere in standby [[UIApplication sharedApplication] setIdleTimerDisabled:NO];   4-­‐93  
  • 94.
    [startButton setTitle:@"Start!"]; //aggiornamento del startButton [locationManager stopUpdatingLocation]; // stop tracking location [locationManager stopUpdatingHeading]; // stop tracking heading mapView.scrollEnabled = YES; // permette all'utente di fare il scroll della map mapView.zoomEnabled = YES; // zoom della mappa // tempo trascorso con l'inizio del percorso float time = -[startDate timeIntervalSinceNow]; // format the ending message with various calculations NSString *message = [NSString stringWithFormat: @"Distanza percorsa: %.02f km, Velocità: %.02f km/h", distance / 1000, distance * 3.6 / time]; // create an alert that shows the message UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Dati percorso.." message:message delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; // show the alert [alert release]; // release the alert UIAlertView } // end if else // inizio misurazione { tracking = YES; // start t mapView.scrollEnabled = NO; mapView.zoomEnabled = NO; // impostazione standby dell'iphone [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; [startButton setTitle: @"Stop"]; // impostazione del titolo del pulsante distance = 0.0; // reset startDate = [[NSDate date] retain]; // memoriazzazione tempo di partenza [locationManager startUpdatingLocation]; // start tracking [locationManager startUpdatingHeading]; // start heading } // } - (void)resetMap { NSLog(@"Sono in reset!"); [trackingView reset]; } -(void)selectMap:(id)sender   4-­‐94  
  • 95.
    { UISegmentedControl *segmentControl = sender; selectedSegment = [segmentControl selectedSegmentIndex]; // impostazione del tipo di map switch (selectedSegment) { // standard map case 0: mapView.mapType = MKMapTypeStandard; break; // satellite map case 1: mapView.mapType = MKMapTypeSatellite; break; // hybrid map case 2: mapView.mapType = MKMapTypeHybrid; break; } // } #pragma mark - #pragma mark MKMapViewDelegate // delegate method for the MKMapView - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation: (id <MKAnnotation>)annotation { return nil; //nessuna annotazione } // #pragma mark - #pragma mark CLLocationManager // the location manager updates the current location - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation: (CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { // nuova posizione sulla mappa [trackingView addPoint:newLocation]; // in caso che c sia una vecchia posizione if (oldLocation != nil) { distance += [newLocation getDistanceFrom:oldLocation]; } // creo una regione centrata attorno al nuovo punto MKCoordinateSpan span = MKCoordinateSpanMake(0.005, 0.005);   4-­‐95  
  • 96.
    // creo unaMKCoordinateRegion centrata attorno alla nuova posizione MKCoordinateRegion region = MKCoordinateRegionMake(newLocation.coordinate, span); [mapView setRegion:region animated:YES]; } // location manager updates the heading - (void)locationManager:(CLLocationManager *)manager didUpdateHeading: (CLHeading *)newHeading { // rotazione in radianti float rotation = newHeading.trueHeading * M_PI / 180; // reset transform mapView.transform = CGAffineTransformIdentity; // creazione di una nuova transform con l'angolo CGAffineTransform transform = CGAffineTransformMakeRotation(-rotation); mapView.transform = transform; // apply the new transform } // CLLocationManager fails - (void)locationManager:(CLLocationManager *)manager didFailWithError: (NSError *)error { if ([error code] == kCLErrorDenied) [locationManager stopUpdatingLocation]; NSLog(@"location manager fallito"); } @end    Codice  21:  Interfaccia  e  implementazione  del  TrackingViewController   4.1.4.1.1.1.1 Interfaccia  Grafica   La   grafica   è   organizzata   attraverso   l’Interface   Builder   con   l’inserimento   nel   view   controller   dell’oggetto   MKMapView   che   è   dimensionato   sull’intera   maschera   e   la   cui   organizzazione   è   delegata   invece  al  codice  che  gestisce  l’invocazione  di  determinati  eventi.     4-­‐96  
  • 97.
      Figura  24:  Interfaccia  grafica  del  TrackingViewController     4.1.4.1.2 TrackingView.   Questo   controller   è   stato   aggiunto   nella   sub-­‐view   dell’elemento   MKMapView:   esso   presenterà   dei   metodi   d’inizializzazione   della   grafica   che   consentiranno   la   loro   gestione   da   codice:   ad   esempio   il   metodo   “drawRect”   sarà   utilizzato   nel   disegno   del   percorso   sulla   mappa,   mentre   i   metodi   “initWithFrame”  e  “addPoint”  serviranno  rispettivamente,  il  primo  ad  inizializzare  il  frame  grafico  del   TrackingViewController,   mentre   il     secondo   ad   aggiungere   i   punti   del   percorso   in   un   array   in   cui   saranno  contenute  le  coordinate  di  ogni  singolo  punto.   Oltre   a   questi   metodi,   implementerà   quelli   relegati   alla   gestione   della   mappa,   come   il   metodo   “regionDidChangedAnimated”   che   aggiornerà   la   “regione”   di   visualizzazione   della   mappa   e   il   “regionWillChangeAnimated”  invocato  quando  la  regione  di  visualizzazione  sarà  cambiata  dall’utente.       #import <UIKit/UIKit.h> #import <MapKit/MapKit.h> #import <CoreLocation/CoreLocation.h> @interface TrackingView : UIView<MKMapViewDelegate> { NSMutableArray *points; } //aggiungo un nuovo punto all'array points - (void)addPoint:(CLLocation *)point; - (void)reset; @end   #import "TrackingView.h" #import <MapKit/MKMapView.h>   4-­‐97  
  • 98.
    static const intARROW_THRESHOLD = 50; @implementation TrackingView - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor clearColor]; // set the background points = [[NSMutableArray alloc] init]; } return self; } - (void)drawRect:(CGRect)rect { if (points.count == 1 || self.hidden) return; // ottengo il contesto grafico corrente CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 4.0); // set the line width CGPoint point; // float distance = 0.0; // initialize distance to 0.0 // ciclo for per tutti i punti for (int i = 0; i < points.count; i++) { float f = (float)i; // cast i as a float and store in f CGContextSetRGBStrokeColor(context, 0, 1 - f / (points.count - 1), f / (points.count - 1), 0.8); CLLocation *nextLocation = [points objectAtIndex:i]; CGPoint lastPoint = point; // store point in lastPoint point = [(MKMapView *)self.superview convertCoordinate: nextLocation.coordinate toPointToView:self]; // se questo non è l’ultimo punto if (i != 0) { // mi muovo dall’ultimo punto CGContextMoveToPoint(context, lastPoint.x, lastPoint.y); // aggiungo una linea CGContextAddLineToPoint(context, point.x, point.y); // add the length of the line drawn to distance   4-­‐98  
  • 99.
    distance += sqrt(pow(point.x- lastPoint.x, 2) + pow(point.y - lastPoint.y, 2)); if (distance >= ARROW_THRESHOLD) { // carico l’immagine della freccia UIImage *image = [UIImage imageNamed:@"arrow.png"]; CGRect frame; // declare frame CGRect // calculate the point in the middle of the line CGPoint middle = CGPointMake((point.x + lastPoint.x) / 2, (point.y + lastPoint.y) / 2); frame.size.width = image.size.width; frame.size.height = image.size.height; frame.origin.x = middle.x - frame.size.width / 2; frame.origin.y = middle.y - frame.size.height / 2; //salvo gli stati grafici CGContextSaveGState(context); // centro il contesto nel quale disegnare la freccia CGContextTranslateCTM(context, frame.origin.x + frame.size.width / 2, frame.origin.y + frame.size.height / 2); //calcolo l’angolo con il quale ruoterò l’immagine della freccia float angle = atan((point.y - lastPoint.y) / (point.x - lastPoint.x)); // se questo punto è a sx dell’ultimo punto if (point.x < lastPoint.x) angle += 3.14159; // incremento l’angolo di pi // ruoto il contesto dell’angolo stabilito CGContextRotateCTM(context, angle); // disegno l’immagine nel contesto ruotato CGContextDrawImage(context, CGRectMake(-frame.size.width / 2, -frame.size.height / 2, frame.size.width,   4-­‐99  
  • 100.
    frame.size.height), image.CGImage); CGContextRestoreGState(context); distance = 0.0; // reset distance } // end if } // end if CGContextStrokePath(context); //disegno il percorso } // end for } // aggiungo un nuovo punto all’array - (void)addPoint:(CLLocation *)point { // store last element of point CLLocation *lastPoint = [points lastObject]; //se il nuovo punto è in una diversa locazione rispetto all’ultimo punto if (point.coordinate.latitude != lastPoint.coordinate.latitude || point.coordinate.longitude != lastPoint.coordinate.longitude) { [points addObject:point]; // aggiungo il punt [self setNeedsDisplay]; // ridisegno la view } // end if } // rimuovo tutti i punti e aggiorno la view - (void)reset { [points removeAllObjects]; [self setNeedsDisplay]; } // end method reset // called by the MKMapView when the region is going to change - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated: (BOOL)animated { self.hidden = YES; // hide the view during the transition } // end method mapView:regionWillChangeAnimated: // called by the MKMapView when the region has finished changing - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { self.hidden = NO; // unhide the view   4-­‐100  
  • 101.
    [self setNeedsDisplay]; //redraw the view } // end method mapview:regionDidChangeAnimated: - (void)dealloc { [super dealloc]; } @end   Codice  22:  Interfaccia  e  implementazione  del  TrackingView   4.2 Lo  sviluppo  del  programma  completo   Per  unire  i  due  gruppi  di  moduli  sviluppati  per  l’applicazione  definitiva,  ovvero  quello  che  implementa   ed  elabora  l’Augmented  Reality  e  quello  che  invece  comprende  le  funzioni  basilari  di  un  navigatore,    si   è  deciso  di  utilizzare  l’elemento  Tab  Bar.   Questo  elemento  è  composto  di  due  o  più  schede  situate  nella  parte  inferiore  della  maschera,  ognuna   delle  quali,  contiene  un  view  controller.  Un  utente,  quindi,  selezionando  una  delle  schede  poste  nel  tab   bar  caricherà  un  view  controller  con  la  vista  associata.     Il  suo  utilizzo  sarà  molto  utile  perché  consentirà  di  presentare  nelle  applicazioni  più  sotto  processi  o   viste  degli  stessi  dati:  ogni  scheda  corrisponderà  a  un  sub-­‐task  dell’applicazione  principale.   Ogni   applicazione   per   Iphone   che   userà   un   tab   bar   dovrà   implementare   nella   classe   che   utilizzerà   i   protocolli  UIApplicationDelegate  e   UITabBarControllerDelegate,   oltre  a  dover  dichiarare  la  proprietà   dell’oggetto  UITabBarController:  questo  permetterà  l’esistenza  dell’oggetto  per  tutto  il  ciclo  di  vita  del   programma.   #import <UIKit/UIKit.h> #import <MapKit/MapKit.h> @interface CompactNavigatorAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> { NSManagedObjectModel *managedObjectModel; NSManagedObjectContext *managedObjectContext; NSPersistentStoreCoordinator *persistentStoreCoordinator; IBOutlet UIWindow *window; IBOutlet UITabBarController *tabBarController; } @property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel; @property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext; @property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator; @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet UITabBarController *tabBarController; - (NSString *)applicationDocumentsDirectory; @end   #import "CompactNavigatorAppDelegate.h" #import "RootViewController.h" @implementation CompactNavigatorAppDelegate   4-­‐101  
  • 102.
    @synthesize window; @synthesize tabBarController; #pragmamark - #pragma mark Application lifecycle - (void)applicationDidFinishLaunching:(UIApplication *)application { // Override point for customization after app launch [window addSubview:tabBarController.view]; [window makeKeyAndVisible]; } /** applicationWillTerminate: saves changes in the application's managed object context before the application terminates. */ - (void)applicationWillTerminate:(UIApplication *)application { NSError *error = nil; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } } #pragma mark - #pragma mark Core Data stack /** Returns the managed object context for the application. If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. */ - (NSManagedObjectContext *) managedObjectContext { if (managedObjectContext != nil) { return managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { managedObjectContext = [[NSManagedObjectContext alloc] init]; [managedObjectContext setPersistentStoreCoordinator: coordinator];   4-­‐102  
  • 103.
    } return managedObjectContext; } /** Returns the managed object model for the application. If the model doesn't already exist, it is created by merging all of the models found in the application bundle. */ - (NSManagedObjectModel *)managedObjectModel { if (managedObjectModel != nil) { return managedObjectModel; } managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain]; return managedObjectModel; } /** Returns the persistent store coordinator for the application. If the coordinator doesn't already exist, it is created and the application's store added to it. */ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (persistentStoreCoordinator != nil) { return persistentStoreCoordinator; } NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"photo.sqlite"]];//CompactNavigator.sqlite NSError *error = nil; persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return persistentStoreCoordinator; } #pragma mark - #pragma mark Application's Documents directory /** Returns the path to the application's Documents directory. */ - (NSString *)applicationDocumentsDirectory {   4-­‐103  
  • 104.
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; } #pragma mark - #pragma mark Memory managemen - (void)dealloc { [managedObjectContext release]; [managedObjectModel release]; [persistentStoreCoordinator release]; [window release]; [super dealloc]; } @end   Codice  23:  Interfaccia  e  implementazione  del  CompactNavigatorAppDelegate   Per   quanto   riguarda   l’impostazione   dell’interfaccia   grafica,   si   dovrà   aprire   il   file   MainView.xib   con   l’Interface   Builder   e   aggiungere   l’oggetto   UITabBarController,   collegandolo   tramite   l’Inspector   alla   proprietà  del  medesimo  tipo  dichiarata  nel  file  CompactNavigatorAppDelegate.       Figura  25:  Impostazione  dell'interfaccia  grafica   A   questo   punto,   s’imposteranno   i   view   controller   per   ogni   scheda   collocata   nel   tab   bar   attraverso   l’Inspector,   alla   voce   “Attributes”,   dove   sarà   settato   il   “nib   file”   e   la   sua   classe   corrispondente   all’interfaccia  grafica  voluta.   Per   completare   infine   i   collegamenti   tra   le   varie   form,   soprattutto   nel   sistema   dell’Augmented   Reality,   si   è   deciso   di   comprendere   nell’insieme   dei   controller   la   barra   di   navigazione   detta   altresì   anche   “navigation  bar”,  con  lo  scopo  di  tenere  sempre  uno  stesso  contesto  tra  un  controller  l’altro.     4-­‐104  
  • 105.
    Questa   parte   è   ottenuta   sia   attraverso   l’editing   da   codice,   creando   le   classi   dei   controller   con   l’implementazione   del   protocollo   “UINavigationControllerDelegate”   e   l’inizializzazione   del   navigation   bar   con   la   creazione   dei   pulsanti   per   consentire   all’utente   d’invocare   determinati   eventi,   sia   tramite   l’Interface   Builder   con   la   predispozione   delle   singole   form   a   visualizzare   la   navigation   bar,   come   mostrato  nella  figura  sottostante.     Figura  26:  Impostazione  della  visualizzazione  della  navigation  bar  sul  MainWindow.xib   Attraverso  l’Xcode,  per  l’editing  del  codice,  le  azioni  correlate  all’implementazione  del  Navigation  bar   potranno  ad  esempio,  essere  le  seguenti:   ⇒ Il  ritorno  a  una  form  precedente  a  quella  aperta   ⇒ L’apertura  di  una  successiva  maschera   ⇒ Il  salvataggio  di  dati   ⇒ L’annullamento  di  una  determinata  azione   Va   ricordato   che   le   azioni   dovranno   essere   associate   a   pulsanti   di   tipo   “UIBarButtonItem”   che   poi   saranno   posti   sul   lato   destro   o   sinistro   della   navigation   bar   attraverso   l’impostazione   delle   seguenti   proprietà:   ⇒ self.navigationItem.leftBarButtonItem  =  cancelButton   ⇒ self.navigationItem.rightBarButtonItem  =  saveButton;   5 COLLAUDO     La  fase  di  collaudo  del  programma  appena  descritto,  deve  essere  attuata  in  primo  luogo  sul  simulatore   disponibile  nel  tool  di  sviluppo  dell’SDK.   Il  problema  principale  è  che  non  tutto  può  essere   simulato  dal  computer;  in  particolare  la  periferica   interna   di   cui   non   si   ha   una   simulazione   è   la   fotocamera,   quindi   per   riuscire   a   far   funzionare   il   programma   è   stato   necessario   inserire   nel   codice,   delle   verifiche   sull’uso   della   periferica   stessa   in   modo  da  non  mandare  in  crash  il  simulatore.     5-­‐105  
  • 106.
    5.1 Collaudo  sull’Iphone  simulator   Per  essere  testato,  il  programma  deve  essere  aperto  tramite  l’Xcode,  il  quale  è  dotato  di  un  pulsante   chiamato   “Build   and   Run”   che   è   delegato   al   caricamento   del   programma   sul   simulatore   e   che   ha   permesso  di  testare  volta  per  volta  il  programma  sviluppato.     Anche  in  questa  fase,  per  agevolare  il  test,  si  è  preferito  comunque  suddividere  il  collaudo  su  più  fasi:   ⇒ Visualizzazione  dei  punti  d’interesse  già  memorizzati;   ⇒ Inserimento  manuale  dei  punti  d’interesse  dell’utente;   ⇒ Distribuzione  dei  POI  memorizzati  internamente  e  disponibili  su  web  service,  sulla  mappa  di   Google  Maps;   ⇒ Simulazione  dell’”Augmented  Reality”;   ⇒ Test  delle  funzionalità  di  navigazione.   Come  già  precisato  in  precedenza,  il  programma  intero  è  stato  suddiviso  in  due  parti,  le  cui  schermate,   sono   rappresentate   qui   di   seguito.   Per   unire   queste   due   parti,   si   è  utilizzato   un   Tab   Bar,   ovvero   una   barra  il  cui  scopo  è  quello  di  unire  “viste  ”  multiple,  che  in  questo  caso  sono  quelle  riguardanti  i  moduli   dell’”Augmented  Reality”  e  i  moduli  inerenti  le  funzioni  di  navigazione.   Per   quanto   concerne   invece   l’accorpamento   delle   viste   di   un   singolo   modulo,   si   è   preferito   l’uso   del   “Navigation  Bar”  che  ha  come  scopo  quello  creare  un  contesto  comune  in  un  “set”  di  form  e  che  può   contenere  pulsanti  atti  ad  invocare  eventi  riguardanti  quella  determinata  vista.           Figura  27:  Descrizione  interfacce  grafiche     5.2 Visualizzazione  dei  punti  d’interesse     Questa   parte   dell’interfaccia,   si   trova   nel   modulo   in   cui   è   implementata   l’Augmented   Reality   e   ha   l’obiettivo  di  visualizzare  i  dati  dei  punti  sotto  forma  di  una  tabella  in  cui  si  renderanno  in  evidenza  i   nomi  degli  stessi  inseriti  dall’utente.   Il   controller   che   è   delegato   a   questa   visualizzazione   è   quello   che   si   trova   nella   figura   27   sul   lato   sinistro:  esso  avrà  il  compito  di  memorizzare,  visualizzare  i  dati  disponibili  e  gestire  le  librerie  dell’AR,   consentendo   all’utente   di   coordinare   tutte   le   form   incaricate   a   svolgere   questi   compiti,   tramite   i   pulsanti  situati  sul  Navigation  Bar.     5-­‐106  
  • 107.
    5.3 Inserimento  manuale  dei  punti  d’interesse  dell’utente   Quando  l’utente  si  troverà  sulla  form,  avrà  la  possibilità  di  compilare  i  campi  riguardanti  il  nome  e  la   descrizione   del   punto   mentre   quelli   riguardanti   la   latitudine   e   la   longitudine   saranno   non   modificabili   e  compilati  dal  programma  con  l’ausilio  del  sensore  GPS.    Eventualmente,  il  cliente,  avrà  la  possibilità   di  scegliere  le  foto  salvate  in  precedenza  del  punto  stesso,  oppure  di  scattarle  direttamente,  gestendo   da  programma  la  fotocamera  con  il  corretto  pulsante.       Figura  28:  Memorizzazione  delle  informazioni  di  un  punto   Se  l’utente  deciderà  di  scegliere  una  delle  foto  presenti  nella  libreria,  allora  dovrà  cliccare  sul  pulsante   “Scegli  foto”  che  aprirà  direttamente  la  libreria  fotografica  dell’Iphone.     Figura  29:  Libreria  fotografica   Altrimenti,   se   vorrà   scattare   una   foto   nuova,   dovrà   premere   il   pulsante   “Click   foto!”   che   andrà   direttamente  a  comandare  la  fotocamera.     5-­‐107  
  • 108.
    5.4 Distribuzione  e  visualizzazione  dei  punti  d’interesse  sulla  mappa   Dalla   maschera   principale   di   visualizzazione   dei   dati   memorizzati   (figura   27),   l’utente,   per   accedere   alla  mappa,  dovrà  premere  il  pulsante  “Map”;  alla  fine  del  suo  caricamento,  potrà  visualizzarvi  i  punti   d’interesse,   sia   quelli   memorizzati   internamente   al   telefono   sia   quelli   scaricati   dal   web   service.   Essi   saranno  identificati  tramite  dei  “pin”  di  colore  verde  che  saranno  sviluppati  in  modo  tale  che  quando   l’utente  ci  cliccherà  sopra,  potrà  visualizzare  le  informazioni  riguardanti  il  loro  nome  e  la  descrizione.     Figura  30:  Visualizzazione  della  mappa  e  delle  informazioni  di  un  punto  d'interesse     5.5 Collaudo  dell’”Augmented  Reality”   L’utente,   trovandosi   nel   controller   dedicato   alla   visualizzazione   dei   dati   memorizzati   nella   memoria   dell’Iphone,   per   accedere   alla   form   dedicata   all’implementazione   dell’Augmented   Reality,   dovrà   dal   navigation  bar  premere  il  pulsante  “System  AR”.   Nel  simulatore,  non  sarà  possibile  provare  in  maniera  diretta  queste  librerie  poiché  il  cuore  del  loro   funzionamento   sarà   incentrato   sulla   gestione   della   fotocamera,   che   nell’Iphone   Simulator   non   riuscirà   a   essere   emulata   in   maniera   perfetta.   Per   evitare   quindi   di   mandare   in   crash   il   sistema,   si   sono   aggiunte  delle  verifiche  per  far  capire  all’applicativo  stesso  se  si  trova  sul  simulatore  oppure  installato   sul  dispositivo.   In   sostanza,   il   controller   non   potendo   sfruttare   la   fotocamera   integrata,   non   inizializzerà   gli   oggetti   dedicati   alla   gestione   della   stessa,   ma   visualizzerà   solamente   i   punti   d’interesse   che   saranno   visibili   ipotizzando   che   l’utente   si   trovi   sulle   coordinate   WGS84   di   Cupertino   e   con   un   determinato   valore   della  bussola,  entrambi  forniti  costantemente  dal  simulatore.     Il   risultato   dato   da   queste   routine   di   verifica   sarà   che   lo   sfondo   della   form,   così   vista   dall’utente   sul   simulatore   sarà   bianco   (a   causa   dell’assenza   della   fotocamera),   mentre   verranno   comunque   visualizzati    i  punti  d’interesse  sullo  schermo  sfruttando  i  valori  delle  coordinate  GPS  e  della  bussola   forniti  dall’emulatore.       5-­‐108  
  • 109.
      Figura  31:  Due  fasi  della  visualizzazione  dei  punti  d'interesse  tramite  l'Augmented  Reality     5.6 Test  delle  funzionalità  di  navigazione   L’utente,  trovandosi  nella  schermata  iniziale  (figura  27),  dovrà  posizionarsi  con  il  cursore  sul  tab  bar  e   cliccare  sulla  scheda  nominata  “Route  Tracker”:  così  facendo  permetterà  al  programma  di  caricare  la   mappa   e   a   caricamento   avvenuto,   l’utente   sarà   localizzato   tramite   un   pin,   attraverso   l’iterazione   del   Mapkit  con  il  frame  work  CoreLocation.   Se  l’utente  deciderà  di  registrare  il  percorso  da  lui  compiuto,  premerà  il  pulsante  “Start”:  il  programma   a  questo  punto,  aumenterà  lo  zoom  sulla  regione  di  mappa,  dove  lui  si  troverà  e  la  ruoterà  sfruttando   la  bussola  interna,  secondo  il  suo  angolo  di  vista.   Va   ricordato   che   nel   collaudo   sul   simulatore,   non   tutte   le   operazioni   descritte   nel   codice   saranno   eseguite  correttamente:  quando  l’utente  premerà  il  bottone  “Start”,  la  mappa  ruoterà  solo  inizialmente   e  non  sarà  disegnato  il  percorso  poiché  il  funzionamento  del  ricevitore  GPS  e  della  bussola,  sarà  solo   una  simulazione  che  fornirà  un  valore  costante.   Quando  l’utente  attiverà  il  pulsante  “Start”,  esso  potrà  in  qualsiasi  momento  fermare  la  registrazione   del   percorso,   tramite   lo   stesso   pulsante   che   cambierà   automaticamente   il   suo   nome   in   “Stop”   per   ricordare   all’utilizzatore   del   programma   la   fine   della   registrazione.   Quando   lo   farà,   il   programma   visualizzerà   i   dati   calcolati   e   resi   disponibili   dal   frame   work   tramite   una   finestra   di   dialogo   che   avviserà  l’utente  della  velocità  media  e  della  distanza  del  percorso  compiuto.   Nel   caso   del   test   su   simulatore,   i   valori   di   velocità   e   distanza   percorsi   saranno   pari   a   zero,   poiché   secondo   il   programma   l’utente   sarà   costantemente   fermo,   com’è   mostrato   nella   seconda   parte   della   figura  sottostante.       5-­‐109  
  • 110.
         Figura  32:  Simulazione  del  modulo  di  navigazione     6 CONCLUSIONI     Il   progetto   sviluppato   in   questa   tesi   è   da   considerarsi   come   prototipo   per   lo   studio   e   l’implementazione  pratica  del  problema  dell’”Augmented  Reality”  sviluppato  su  piattaforma  Iphone.   Esso   è   stato   elaborato   partendo   dall’ipotesi   che   si   doveva   ottenere   un   programma   in   grado   di   riconoscere  tramite  il  sensore  della  fotocamera  gli  oggetti  circostanti,  partendo  dall’idea  che  l’utente   stesso  si  dovesse  trovare  “immerso”  in  quel  determinato  ambiente  .       6-­‐110  
  • 111.
    Alla   fine,   quindi   si   è   ottenuto   un   programma   in   grado   di   risolvere   questo   problema,   implementando   le   librerie   chiamate   ”Iphone   ARKit”   e   facendole   interagire   con   un   database   interno   per   i   POI   (punti   d’interesse)  personali  dell’utente  e  con  un  web  service  per  i  punti  disponibili  su  un  database  remoto,   con  lo  scopo  poi  di  elaborarli  successivamente  ad  esempio  per  la  loro  localizzazione  su  una  mappa.   In   un   secondo   momento,   si   è   deciso   di   aggiungere   all’applicativo   finora   sviluppato   delle   elementari   funzioni   di   navigazione,   tenendo   presente   sempre   che   il   programma   doveva   rispettare   dei   vincoli   di   leggerezza  nei  caricamenti  dati:  si  è  stabilito  quindi  che  le  mappe  necessarie  alla  navigazione  fossero   quelle  disponibili  direttamente  dalla  rete  (nel  caso  di  questo  programma,  quelle  di  Google  Maps®)  e   che   l’utente   potesse   inoltre   tracciare   sulle   stesse,   il   percorso   compiuto   dal   dispositivo   in   un   determinato  tempo.   6.1 Pregi  e  difetti  individuati  nel  programma   6.1.1 Pregi   Per   quanto   concerne   i   pregi   di   questo   programma   descritto,   si   capisce   che   può   essere   adattabile   e   integrabile  per  svariati  scopi:  lo  sviluppatore  potrà  quindi  decidere  ad  esempio  quali  dati  utili  estrarre   dalla  memoria  del  dispositivo  o  dal  web  service  utilizzato  e  adattare  l’interfaccia  grafica  ai  suoi  scopi,   soprattutto  nella  parte  riguardante  l’”Augmented  Reality”.   Dalla   parte   invece   del   cliente   che   utilizzerà   il   programma,   sarà   evidente   la   semplificazione   nel   caricamento   delle   mappe   nelle   interfacce   grafiche   in   quanto,   non   sarà   richiesta   la   memorizzazione   delle  stesse  nella  memoria  del  telefono,  ma  il  tutto  sarà  delegato  alla  rete.     I   dati   utilizzati   nell’AR,   inoltre   saranno   molto   utili   per   un   utilizzo   sul   campo   dell’applicazione   stessa   come   uno   strumento   aggiuntivo   di   navigazione,   per   l’individuazione   di   determinati   tipi   di   punti   d’interesse  scelti  a  priori  dallo  sviluppatore.   6.1.2 Difetti   I  difetti  riscontrati  alla  fine  della  realizzazione  del  progetto,  possono  essere  sintetizzati  in  tre  punti:   1. L’impossibilità  di  trasferire  i  dati  memorizzati  su  un  altro  Iphone   2. La  dipendenza  del  programma  dal  collegamento  ad  internet   3. Il  consumo  eccessivo  della  batteria   Il  primo  è  un  difetto  importante  poiché  grazie  a  questo,  non  è  possibile  realizzare  un’implementazione   dello  stesso  software  contenente  gli  stessi  dati  su  molteplici  dispositivi.  Esso  quindi  fino  a  quando  non   verrà  risolto,  sarà  da  considerarsi  come  la  principale  mancanza  di  questo  programma  che  potrà  altresì   essere  usato  come  una  sorta  di  guida  individuale  dell’utente.     Il  secondo  sarà  considerato  una  carenza  marginale  in  quanto  limiterà  il  funzionamento  dell’applicativo   in  maniera  parziale:  le  funzioni  quindi  disabilitate  saranno  quelle  del  caricamento  dei  punti  d’interesse   prelevati  dal  web  service  e  i  caricamenti  delle  mappe  che  come  già  scritto  saranno  delegate  ad   internet,  mentre  la  parte  riguardante  l’”Augmented  Reality”  funzionerà  ugualmente.   Il  terzo  problema,  al  contrario  non  potrà  essere  risolto  dal  programmatore,  ma  dovrà  essere  appianato   dal  costruttore,  perché  questo  programma  richiedendo  l’accesso  alla  rete  e  al  GPS,  esigerà  una   notevole  quantità  di  corrente  che  conseguentemente  farà  diminuire  l’autonomia  del  telefono.   6.1.3 Sviluppi  futuri   Essendo  questo  progetto  un  prototipo  che  implementa  l’”Augmented  Reality”,  su  questa  base  potrà   essere  realizzato  un  programma  che  permetterà  all’utente  di  utilizzare  più  web  services  assieme   poiché  al  momento  attuale,  se  ne  è  implementato  solamente  uno  singolo.   Scegliendo  quindi  d’implementare  più  servizi,  si  darà  l’opportunità  all’utente  di  possedere  uno   strumento  ancora  più  ricco  d’informazioni  utili  nella  navigazione  e  quindi  per  il  caricamento  di  nuovi   punti  sia  nell’AR,  sia  sulle  mappe.       6-­‐111  
  • 112.
    Inoltre,  per  rendere  disponibili  gli  stessi  punti  sulla  memoria  interna  di  molteplici  Iphone,  potrà  essere   sviluppato  separatamente  al  programma,  un  server,  nel  quale  saranno  memorizzati  i  punti  da  inserire   in  memoria  dei  telefoni,  sempre  nell’ipotesi  che  gli  stessi  siano  utilizzati  da  un  ente  come,  ad  esempio,   “guide  turistiche”  di  una  determinata  località.     6-­‐112  
  • 113.
    7 BIBLIOGRAFIA     Per  lo  sviluppo  di  questo  progetto,  i  documenti  che  sono  stati  utili,  sono  stati  quelli  del  portale  della   Apple  per  gli  sviluppatori,  posto  all’indirizzo     http://developer.apple.com/iphone/index.action   Dove  il  programmatore  può  trovare  tutti  i  tutorial  necessari  all’apprendimento  dell’Objective  C  e  delle   guide  utili  allo  sviluppo  di  programmi  funzionanti.   Da   segnalare   inoltre   un   altro   sito   internet   molto   utile,   in   cui   sono   disponibili   delle   lezioni   on   line   sulle   basi  di  programmazione  dell’Objective  C,  redatte  dall’Università  di  Stanford  e  reperibili  all’indirizzo     http://www.stanford.edu/class/cs193p/cgi-­bin/drupal/downloads-­2010-­winter   Mentre  per  quanto  riguarda  la  trattazione  di  singoli  problemi,  attraverso  articoli  scritti  direttamente   da  sviluppatori  indipendenti,  per  la  programmazione  su  Iphone,  bisogna  segnalare  questo  sito     http://icodeblog.com/   8 RINGRAZIAMENTI     Per   il   lavoro   svolto,   devo   innanzitutto   ringraziare   il   professor   Giorgio   Manzoni,   per   avermi   dato   la   possibilità   di   realizzare   un   suo   progetto,   la   professoressa   Raffaela   Cefalo   invece   per   avermi   fatto   conoscere  le  materie  riguardanti  la  topografia  e  dato  un  supporto  per  lo  svolgimento  della  tesi  e  del   tirocinio,   Sara,   una   persona   che   mi   è   stata   vicina   negli   ultimi   2   anni,   in   particolare   in   questo   interminabile   periodo,   i   genitori   per   avermi   dato   la   possibilità   di   frequentare   l’università   e   anche   di   terminarla.   Un  saluto  va  anche  ai  miei  nonni  che  non  ci  sono  più,  in  particolare  a  nonno  Alberto  appassionato  di   informatica  che  ha  visto  l’inizio  della  mia  carriera  universitaria,  ma  non  la  fine.     8-­‐113