Inoltra geocoding con CLG eocoder

Con l'introduzione di iOS 5, centinaia di nuove API sono diventate disponibili per gli sviluppatori iOS. Una delle funzionalità meno pubblicizzate era l'aggiunta di un'API di geocoding come parte del framework Core Location. La classe che gestisce le richieste di geocodifica è CLGeocoder. Nei prossimi venti minuti, ti mostrerò come costruire un'applicazione che converte un indirizzo fisico in una coppia di coordinate usando CLGeocoder.

Cos'è la geocoding? Geocoding è una parola di fantasia per associare una coppia di coordinate con un indirizzo fisico (reverse geocoding) e viceversa (geocoding in avanti). Anche se MapKit ha avuto la possibilità di invertire le coordinate geografiche con MKReverseGeocoder dal rilascio di iOS 3, MKReverseGeocoder è stato deprecato da iOS 5. CLGeocoder gestisce la geocodifica in iOS 5 e lo fa in modo semplice ed elegante. Come indica il nome, CLGeocoder fa parte del potente framework Core Location. Oltre al geocoding inverso, CLGeocoder può anche tradurre gli indirizzi fisici in posizioni (geocoding in avanti) e questo è esattamente ciò che faremo in questo tutorial.

Creeremo un'applicazione che consente all'utente di inserire una strada, una città e un paese e la nostra applicazione restituirà una latitudine e una longitudine per l'indirizzo nonché un possibile nome della posizione, una cosiddetta area di interesse.

Come fa CLGeocoder Fai questo? Il framework Core Location si connette a un servizio Web dietro le quinte, ma tu, come sviluppatore, non hai a che fare con i dettagli nitty grintosi. CLGeocoder è quindi molto facile da usare.


Passaggio 1: Impostazione del progetto

Accendi Xcode e crea un nuovo progetto scegliendo il Applicazione vista singola modello. Assegna un nome all'applicazione Geocoding, inserisci un identificativo aziendale, seleziona iPhone per la famiglia di dispositivi e assicurati di controllare Utilizzare il conteggio di riferimento automatico. Puoi lasciare il Prefisso di classe campo vuoto e le caselle rimanenti deselezionate. Scegli una posizione per salvare il tuo progetto e premi Creare.


Passaggio 2: creazione dell'interfaccia utente

Iniziamo creando l'interfaccia utente della nostra applicazione. Prima di aprire il file XIB del nostro controller di visualizzazione, tuttavia, dobbiamo creare sei uscite e una sola azione. Seleziona il file di intestazione del controller di visualizzazione e dichiara le prese e l'azione come mostrato nello snippet seguente.

 #importare  @interface ViewController: UIViewController __weak UITextField * _streetField; __basso UITextField * _cityField; __basso UITextField * _countryField; __basso UIButton * _fetchCoordinatesButton; __basso UILabel * _nomeLabel; __basso UILabel * _coordinatesLabel;  @property (nonatomic, weak) IBOutlet UITextField * streetField; @property (nonatomic, weak) IBOutlet UITextField * cityField; @property (nonatomic, weak) IBOutlet UITextField * countryField; @property (nonatomic, weak) IBOutlet UIButton * fetchCoordinatesButton; @property (nonatomic, weak) IBOutlet UILabel * nameLabel; @property (nonatomic, weak) IBOutlet UILabel * coordinatesLabel; - (IBAction) fetchCoordinates: (id) mittente; @fine

Le prime tre uscite sono istanze di UITextField in cui l'utente può inserire una strada, una città e un paese. La quarta uscita è un'istanza di UIButton che attiverà la nostra azione quando l'utente lo toccherà. Gli ultimi due punti vendita sono istanze di UILabel che useremo per visualizzare i risultati della nostra richiesta di geocoding. Se la nostra richiesta di geocodifica viene restituita correttamente, mostreremo il nome della posizione nella prima etichetta (più avanti in seguito) e le coordinate della posizione nella seconda etichetta. Non ti preoccupare se questo ti confonde. Avrà più senso una volta che colleghiamo tutto nel nostro file xib.

Dichiariamo anche un metodo che (1) attiva e (2) gestisce la nostra richiesta di geocoding. Questa azione sarà collegata al nostro pulsante. Ti stai chiedendo perché abbiamo bisogno di uno sbocco per il nostro pulsante? Ti dirò di più al termine di questo tutorial.

Non dimenticare di sintetizzare gli accessor per i punti vendita. Dovresti anche creare un'implementazione vuota della nostra azione per evitare eventuali avvisi del compilatore.

 @synthesize streetField = _streetField, cityField = _cityField, countryField = _countryField, fetchCoordinatesButton = _fetchCoordinatesButton, nameLabel = _nomeLabel, coordinatesLabel = _coordinatesLabel; - (IBAction) fetchCoordinates: (id) sender NSLog (@ "Fetch Coordinates"); 

Pronto? Andate al file xib del nostro controller di visualizzazione e trascinate tre campi di testo, un pulsante e due etichette nella vista del controller della vista. Posizionali come nella figura qui sotto e dai il titolo al pulsante Recupera coordinate per far sapere all'utente cosa accadrà quando il pulsante viene toccato.

Assicurati di aggiungere un segnaposto a ciascun campo di testo per consentire all'utente di sapere che tipo di informazioni si aspetta ogni campo di testo. Ho anche configurato le etichette per avere testo bianco su sfondo blu per far risaltare.

Vediamo quello che abbiamo finora. L'utente può inserire una strada e un numero nel primo campo di testo, una città nel secondo campo di testo e un paese nel terzo campo di testo. Quando l'utente tocca il Recupera coordinate pulsante, la nostra applicazione effettuerà una richiesta di georeferenziazione per l'indirizzo inserito dall'utente. Se la nostra richiesta ha esito positivo, mostriamo il nome della posizione e le coordinate (latitudine e longitudine) nelle etichette.

Con l'interfaccia utente in atto, siamo pronti a collegare i nostri punti vendita e le nostre azioni. Per le prese, premere il tasto CTRL e trascinare da Proprietario del file ai campi di testo e scegliere l'appropriato IBOutlet dal menu che si apre. Fai lo stesso per il pulsante e le etichette. Per l'azione, premi ancora una volta il tasto control e trascina dal nostro pulsante su Proprietario del file e scegli il fetchCoordinates: metodo dal menu che appare. Questo collegherà la nostra azione ai pulsanti UIControlEventTouchUpInside evento e questo è esattamente ciò che vogliamo.


Passaggio 3: aggiunta della posizione principale al mix

Prima di iniziare a implementare il fetchCoordinates: metodo, abbiamo bisogno di aggiungere il Core Location quadro del nostro progetto. Seleziona il nostro progetto nel Project Navigator e scegli l'unico bersaglio nell'elenco dei bersagli. In alto, scegli il Costruisci fasi scheda e apri il Collega binario con le librerie cassetto. Colpire il segno più e scegliere Core Location dalla lista che si apprezza. Il nostro progetto è ora collegato al framework Posizione principale.

C'è un'ultima cosa che dobbiamo fare prima di poter utilizzare il framework Core Location. Torna al file di intestazione del controller di visualizzazione e aggiungi una nuova istruzione di importazione sotto l'istruzione di importazione di UIKit.

 #importare  #importare 

L'istruzione import importa le intestazioni del framework della posizione principale e garantisce che possiamo utilizzare le sue funzionalità nel nostro controller di visualizzazione. Abbiamo anche bisogno di creare una variabile di istanza per l'oggetto geocoder che useremo per fare richieste di geocodifica. Come ho detto all'inizio di questo tutorial, useremo un'istanza di CLGeocoder per questo scopo. Aggiungi una variabile di istanza e una proprietà al file di intestazione del tuo controller di visualizzazione e non dimenticare di sintetizzare i suoi accessor nel file di implementazione del tuo controller di visualizzazione. Ora siamo pronti a fare un po 'di magia.

 #importare  #importare  @interface ViewController: UIViewController CLGeocoder * _geocoder; __basso UITextField * _streetField; __basso UITextField * _cityField; __basso UITextField * _countryField; __basso UIButton * _fetchCoordinatesButton; __basso UILabel * _nomeLabel; __basso UILabel * _coordinatesLabel;  @property (nonatomic, strong) CLGeocoder * geocoder; @property (nonatomic, weak) IBOutlet UITextField * streetField; @property (nonatomic, weak) IBOutlet UITextField * cityField; @property (nonatomic, weak) IBOutlet UITextField * countryField; @property (nonatomic, weak) IBOutlet UIButton * fetchCoordinatesButton; @property (nonatomic, weak) IBOutlet UILabel * nameLabel; @property (nonatomic, weak) IBOutlet UILabel * coordinatesLabel; - (IBAction) fetchCoordinates: (id) mittente; @fine
 // Ricorda di sintetizzare il geocoder: @synthesize geocoder = _geocoder; - (IBAction) fetchCoordinates: (id) sender NSLog (@ "Fetch Coordinates"); 

Passaggio 4: Inoltra geocoding

Attraverserò il fetchCoordinates: metodo passo dopo passo. Per prima cosa controlliamo se la nostra istanza di geocoder è impostata. Se questo non è il caso, lo inizializziamo. Spesso è buona norma inizializzare un oggetto solo quando ne hai effettivamente bisogno.

 if (! self.geocoder) self.geocoder = [[CLGeocoder alloc] init]; 

In questo esempio faremo una richiesta di geocodifica in avanti, il che significa che invieremo un indirizzo al servizio web a cui si riferisce la posizione centrale e che ci invierà i dati sulla posizione. Il metodo che useremo accetta una stringa di indirizzo, il che significa che dobbiamo concatenare i dati dell'indirizzo dai nostri campi di testo.

 NSString * address = [NSString stringWithFormat: @ "% @% @% @", self.streetField.text, self.cityField.text, self.countryField.text];

Infine, chiamiamo geocodeAddressString: completionHandler: sul nostro oggetto geocoder. Questo metodo accetta due argomenti: (1) la nostra stringa di indirizzo e (2) un blocco di completamento. Questa è un'altra bella applicazione di blocchi che dimostra il potere che sfruttano.

 [self.geocoder geocodeAddressString: address completionHandler: ^ (segnaposto NSArray *, errore NSError *) if ([placemarks count]> 0) CLPlacemark * placemark = [placemarks objectAtIndex: 0]; CLLocation * location = placemark.location; Coordinazione CLLocationCoordinate2 = location.coordinate; self.coordinatesLabel.text = [NSString stringWithFormat: @ "% f,% f", coordinate.latitudine, coordinate.lunghezza]; if ([placemark.areasOfInterest count]> 0) NSString * areaOfInterest = [placemark.areasOfInterest objectAtIndex: 0]; self.nameLabel.text = areaOfInterest;  else self.nameLabel.text = @ "Non è stata trovata alcuna area di interesse"; ];

Il blocco di completamento prende due argomenti, (1) un array di posizioni (i cosiddetti segnaposto) e (2) un errore nel caso qualcosa vada storto. Perché otteniamo una serie di posizioni invece di una sola posizione? Quando l'indirizzo che inviamo al servizio web non è abbastanza specifico, è possibile che il servizio web restituisca non uno, ma diversi segnaposto che corrispondono all'indirizzo. Diversi cosa? Un segnaposto, un esempio di CLPlacemark, è un contenitore per i dati associati a una coppia di coordinate. Contiene oltre alle coordinate, come la strada, la città e il paese, nonché le aree di interesse, come edifici, parchi nazionali e monumenti storici.

Per il nostro progetto, vogliamo solo le coordinate del segnaposto e dell'area di interesse, se ce n'è una. Ti invito a registrare l'intera serie di segnaposto sulla console per vedere cosa contiene. Questo è sempre un buon modo per esplorare nuove API.

Nel nostro blocco di completamento, per prima cosa controlliamo se la nostra serie di segnaposto contiene oggetti, in altre parole, il servizio web è stato in grado di associare una posizione al nostro indirizzo. Se abbiamo una matrice non vuota, prendiamo il primo oggetto. Naturalmente, in una vera applicazione potresti voler fare un controllo degli errori per assicurarti di aver trovato un segnaposto che ti interessa e anche assicurarti che l'errore del blocco di completamento sia pari a zero.

Una delle proprietà di un'istanza CLPlacemark è la sua posizione, che è a CLLocation oggetto. Se non hai familiarità con CLLocation oggetti, contengono le coordinate (CLLocationCoordinate2D) che stiamo cercando, ma anche una misura per l'accuratezza del luogo. CLLocation gli oggetti sono usati in tutto il framework Core Location e sono incredibilmente utili.

Per visualizzare il risultato della nostra richiesta sullo schermo, prendiamo la latitudine e la longitudine della proprietà posizione del segnaposto e la mostriamo nella nostra etichetta. Controlliamo anche se la serie di aree di interesse del segnaposto non è vuota. Se lo è, quindi prendiamo il primo oggetto che contiene (un'istanza di NSString) e mostrarlo nella nostra prima etichetta. Se non sono state trovate aree di interesse, comunichiamo all'utente visualizzando un semplice messaggio.

Voglio aggiungere un ultimo tocco al nostro applicin per migliorare l'esperienza dell'utente e anche per seguire le linee guida di Apple. Quando facciamo una richiesta di geocoding, non otteniamo una risposta immediata. Come accennato in precedenza, il framework Posizione principale parla con un servizio Web e riceve una risposta. Quando arriva la risposta dipende da vari fattori, come la velocità della nostra connessione di rete. La documentazione di CLGeocoder afferma che le richieste al webserivce dovrebbero essere fatte con parsimonia. In altre parole, l'utente (1) non dovrebbe effettuare più richieste in un breve intervallo di tempo toccando il pulsante più volte e (2) l'utente non dovrebbe essere in grado di fare una richiesta prima che la richiesta attiva abbia restituito una risposta. Per realizzare quest'ultimo, disabilitiamo il pulsante fino a quando la richiesta è finita (con successo o senza successo). Per fare ciò, disabilitiamo il pulsante prima di effettuare la richiesta e di attivare nuovamente il pulsante nel blocco di completamento. Dai un'occhiata alla completa implementazione del nostro fetchCoordinates: metodo di chiarimento. Esegui la tua domanda e inserisci un indirizzo per metterlo alla prova.

 - (IBAction) fetchCoordinates: (id) sender if (! Self.geocoder) self.geocoder = [[CLGeocoder alloc] init];  NSString * address = [NSString stringWithFormat: @ "% @% @% @", self.streetField.text, self.cityField.text, self.countryField.text]; self.fetchCoordinatesButton.enabled = NO; [self.geocoder geocodeAddressString: address completionHandler: ^ (segnaposto NSArray *, errore NSError *) if ([placemarks count]> 0) CLPlacemark * placemark = [placemarks objectAtIndex: 0]; CLLocation * location = placemark.location; Coordinazione CLLocationCoordinate2 = location.coordinate; self.coordinatesLabel.text = [NSString stringWithFormat: @ "% f,% f", coordinate.latitudine, coordinate.lunghezza]; if ([placemark.areasOfInterest count]> 0) NSString * areaOfInterest = [placemark.areasOfInterest objectAtIndex: 0]; self.nameLabel.text = areaOfInterest;  self.fetchCoordinatesButton.enabled = YES; ]; 

Potremmo fare un ulteriore passo avanti visualizzando un indicatore di attività durante la richiesta e nascondendo il pulsante, ma lascio a te una sfida. Ho aggiunto questa funzionalità al codice sorgente che accompagna questo tutorial.


Conclusione

Core Location è diventato un framework molto potente e CLGeocoder è solo una delle tante classi che ti aiutano a svolgere un compito complesso con facilità e pochissimo overhead. Godere!