Transmiterea geocodului cu CLGeocoder

Odată cu introducerea iOS 5, sute de noi API-uri au devenit disponibile dezvoltatorilor iOS. Una dintre caracteristicile mai puțin cunoscute a fost adăugarea unui API geocoding, ca parte a cadrului Core Location. Clasa de manipulare a cererilor de geocod este CLGeocoder. În următoarele douăzeci de minute, vă voi arăta cum să construiți o aplicație care convertește o adresă fizică într-o pereche de coordonate utilizând CLGeocoder.

Ce este geocodarea? Geocodul este un cuvânt fantezist pentru asocierea unei perechi de coordonate cu o adresă fizică (geocodarea inversă) și invers (geocodarea în față). Chiar dacă MapKit a avut capacitatea de a inversa coordonatele geocodului MKReverseGeocoder de la lansarea iOS 3, MKReverseGeocoder a fost depreciat ca de iOS 5. CLGeocoder gestionează geocodarea în iOS 5 și o face într-un mod simplu și elegant. După cum indică și numele, CLGeocoder face parte din cadrul puternic de localizare a nucleului. În plus față de geocodarea inversă, CLGeocoder poate traduce și adrese fizice în locații (geocodificare în față) și exact ceea ce vom face în acest tutorial.

Vom construi o aplicație care permite utilizatorului să acceseze o stradă, un oraș și o țară, iar aplicația noastră va returna o latitudine și longitudine pentru adresă, precum și un nume posibil al locației, o așa-numită zonă de interes.

Cum se CLGeocoder fa asta? Cadrul de bază a locației se conectează la un serviciu web din spatele scenei, dar, ca dezvoltator, nu trebuie să vă ocupați de detalii. CLGeocoder este, prin urmare, foarte ușor de utilizat.


Pasul 1: Configurarea proiectului

Activați Xcode și creați un nou proiect selectând Vizualizare individuală șablon. Denumiți aplicația Geocoding, introduceți un identificator al companiei, selectați iPhone pentru familia de dispozitive și asigurați-vă că ați verificat Utilizați numărarea automată a referințelor. Puteți să părăsiți Prefix de clasă câmpul gol și casetele rămase neefectuate. Alegeți o locație pentru a vă salva proiectul și a lovi Crea.


Pasul 2: Crearea interfeței utilizator

Începem prin crearea interfeței de utilizare a aplicației noastre. Înainte de a deschide fișierul XIB al controlorului de vizualizare, cu toate acestea, trebuie să creăm șase puncte de vânzare și o acțiune. Selectați fișierul antet al controlerului de vizualizare și declarați punctele de desfacere și acțiunea așa cum se arată în fragmentul de mai jos.

 #import  @ interfață ViewController: UIViewController __weak UITextField * _streetField; __weak UITextField * _cityField; __weak UITextField * _countryField; __weak UIButton * _fetchCoordinatesButton; __weak UILabel * _nameLabel; __weak UILabel * _coordinatesLabel;  @property (nonatomic, slab) IBOutlet UITextField * streetField; @property (nonatomic, slab) IBOutlet UITextField * cityField; @property (nonatomic, slab) IBOutlet UITextField * countryField; @property (nonatomic, slab) IBOutlet UIButton * fetchCoordinatesButton; @property (nonatomic, slab) IBOutlet UILabel * nameLabel; @property (nonatomic, slab) IBOutlet UILabel * coordinatesLabel; - (IBAction) fetchCoordonate: (id) expeditor; @Sfârșit

Primele trei puncte de ieșire sunt cazuri de UITextField în care utilizatorul poate introduce o stradă, un oraș și o țară. A patra priză este o instanță de UIButton care va declanșa acțiunea noastră atunci când utilizatorul o intervine. Cele două puncte de vânzare finale sunt cazuri de UILabel pe care o vom folosi pentru a afișa rezultatele cererii noastre de geocodificare. Dacă cererea noastră de codificare geografică se întoarce cu succes, vom afișa numele locației în prima etichetă (mai multe despre aceasta mai târziu) și coordonatele locației din a doua etichetă. Nu vă faceți griji dacă vă derutează acest lucru. Va face mai multă sens când vom face totul în fișierul nostru xib.

De asemenea, declarăm o metodă care va (1) declanșa și (2) manipula cererea noastră de codificare. Această acțiune va fi cuplată la butonul nostru. Te întrebi de ce avem nevoie de o priză pentru butonul nostru? Vă voi spune mai multe despre asta la sfârșitul acestui tutorial.

Nu uitați să sintetizați accesoriile pentru prize. De asemenea, trebuie să creați o implementare goală a acțiunii noastre pentru a evita avertismentele compilatorului.

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

Gata? Treceți la fișierul xib al controlerului de vizualizare și trageți trei câmpuri de text, un buton și două etichete la vizualizarea controlerului dvs. de vizualizare. Poziționați-le ca în figura de mai jos și dați butonul un titlu Luați coordonatele pentru a lăsa utilizatorul să știe ce se va întâmpla la atingerea butonului.

Asigurați-vă că adăugați un substituent în fiecare câmp text pentru a permite utilizatorului să știe ce tip de informație așteaptă fiecare câmp de text. De asemenea, am configurat etichetele să aibă un text alb pe un fundal albastru pentru al lăsa să iasă în evidență.

Să vedem ce avem până acum. Utilizatorul poate introduce o stradă și un număr în primul câmp de text, un oraș în al doilea câmp de text și o țară în al treilea câmp de text. Atunci când utilizatorul pune în funcțiune Luați coordonatele , aplicația noastră va face o solicitare de codificare geografică pentru adresa pe care a introdus-o utilizatorul. Dacă cererea noastră are succes, vom afișa numele etichetei în locația și coordonatele (latitudine și longitudine).

Cu interfața cu utilizatorul instalată, suntem pregătiți să ne concretizeze punctele de vânzare și acțiunile noastre. Pentru prizele de alimentare, apăsați tasta de control și trageți din Proprietarul dosarului la câmpurile de text și alegeți corespunzător IBOutlet din meniul care apare. Faceți același lucru pentru buton și etichete. Pentru acțiune, apăsați încă o dată tasta de control și glisați de la butonul nostru la Proprietarul dosarului și alegeți fetchCoordinates: din meniul care apare. Aceasta va conecta acțiunea noastră la butoanele UIControlEventTouchUpInside eveniment și asta este exact ceea ce vrem.


Pasul 3: Adăugarea locației de bază a mixului

Înainte de a începe implementarea fetchCoordinates: metoda, trebuie să adăugăm Locația centrală cadru pentru proiectul nostru. Selectați proiectul nostru în Project Navigator și alegeți singurul țintă din lista de obiective. În partea de sus, alegeți Construiți faze și deschideți fereastra Link binar cu biblioteci sertar. Apăsați semnul plus și alegeți Locația centrală din lista care apare. Proiectul nostru este acum legat de cadrul de locație centrală.

Există un ultim lucru pe care trebuie să-l facem înainte de a putea folosi cadrul de locație centrală. Navigați înapoi la fișierul de antet al controlorului nostru de vizualizare și adăugați o nouă declarație de import sub declarația de import UIKit.

 #import  #import 

Instrucțiunea de import importează anteturile de bază pentru locația de bază și asigură că putem utiliza funcționalitatea acesteia în controlerul nostru de vizualizare. De asemenea, trebuie să creați o variabilă de instanță pentru obiectul geocoder pe care îl vom folosi pentru a face cereri de codificare geocod. Așa cum am menționat la începutul acestui tutorial, vom folosi un exemplu de CLGeocoder în acest scop. Adăugați o variabilă de instanță și o proprietate în fișierul de antet al controlerului de vizualizare și nu uitați să-i sintetizați accesorii în fișierul de implementare a controlerului de vizualizare. Suntem gata să facem niște magie.

 #import  #import  @interface ViewController: UIViewController CLGeocoder * _geocoder; __weak UITextField * _streetField; __weak UITextField * _cityField; __weak UITextField * _countryField; __weak UIButton * _fetchCoordinatesButton; __weak UILabel * _nameLabel; __weak UILabel * _coordinatesLabel;  @property (nonatomic, puternic) CLGeocoder * geocoder; @property (nonatomic, slab) IBOutlet UITextField * streetField; @property (nonatomic, slab) IBOutlet UITextField * cityField; @property (nonatomic, slab) IBOutlet UITextField * countryField; @property (nonatomic, slab) IBOutlet UIButton * fetchCoordinatesButton; @property (nonatomic, slab) IBOutlet UILabel * nameLabel; @property (nonatomic, slab) IBOutlet UILabel * coordinatesLabel; - (IBAction) fetchCoordonate: (id) expeditor; @Sfârșit
 // Rețineți să sintetizați geocoderul: @synthesize geocoder = _geocoder; - (IBAction) fetchCoordonate: (id) expeditor NSLog (@ "Fetch Coordinates"); 

Pasul 4: Geocodarea înainte

Voi trece prin fetchCoordinates: metoda pas cu pas. Mai întâi verificăm dacă instanța noastră geocoder este setată. Dacă nu este cazul, îl inițializăm. Este adesea o bună practică să inițializați un obiect doar atunci când aveți nevoie de el.

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

În acest exemplu, vom face o cerere de codificare geocod, ceea ce înseamnă că trimitem o adresă la serviciul web la care discută Core Locația și va trimite datele despre locație înapoi la noi. Metoda pe care o vom folosi acceptă un șir de adresă, ceea ce înseamnă că trebuie să concatenăm datele de adresă din câmpurile noastre de text.

 NSString * adresa = [NSString șirWithFormat: @ "% @% @% @", self.streetField.text, self.cityField.text, self.countryField.text];

În cele din urmă, sunăm geocodeAddressString: completionHandler: pe obiectul geocoder. Această metodă acceptă două argumente: (1) șirul de adresă și (2) un bloc de completare. Aceasta este o altă aplicare clară a blocurilor care demonstrează puterea pe care o exploatează.

 [auto.geocoder geocodeAddressString: adresa de completareHandler: ^ (NSArray * marcatori de locație, eroare NSError *) if ([numărul de marcatori]> 0) CLPlacemark * marcator de locație = [locații objectAtIndex: 0]; Locația CLL * location = Locație locație; CLLlocațieCoordinate2D coordinate = location.coordinate; self.coordinatesLabel.text = [NSString șirWithFormat: @ "% f,% f", coordonate.latitude, coordinate.longitude]; dacă ([marcajul.articol.articolar]]> 0) NSString * areaOfInterest = [marcator.articol.articol]; auto.nameLabel.text = areaOfInterest;  altceva self.nameLabel.text = @ "Nu a fost găsită nicio zonă de interes"; ];

Blocul de completare are două argumente, (1) o serie de locații (așa-numitele marcatori de locație) și (2) o eroare în cazul în care ceva nu merge bine. De ce obținem o serie de locații în loc de o singură locație? Atunci când adresa pe care o trimitem serviciului web nu este suficient de specifică, este posibil ca serviciul web să nu returneze unul, ci mai multe marcaje de locație care se potrivesc cu adresa. Mai multe ce? Un marcator de locație, o instanță de CLPlacemark, este un container pentru date asociate cu o pereche de coordonate. Conține mai mult decât coordonatele, cum ar fi strada, orașul și țara, precum și zonele de interes, cum ar fi clădirile, parcurile naționale și monumentele istorice.

Pentru proiectul nostru, dorim doar coordonatele marcatorului de locație și zona de interes dacă există unul. Vă încurajez să înregistrați întreaga gamă de marcatori de locație la consola pentru a vedea ce conține. Aceasta este întotdeauna o modalitate bună de a explora noi API-uri.

În blocul de completare, verificăm mai întâi dacă matricea de marcatori de locație conține obiecte, cu alte cuvinte, serviciul web a putut să asocieze o locație cu adresa noastră. Dacă avem o matrice non-goală, luăm primul obiect. Desigur, într-o aplicație reală ați putea dori să faceți o verificare a erorilor pentru a vă asigura că ați găsit un marcator de locație care vă interesează și, de asemenea, asigurați-vă că eroarea blocului de completare este zero.

Una dintre proprietățile unui exemplu CLPlacemark este locația sa, care este a CLLocation obiect. Dacă nu sunteți familiarizați cu CLLocation obiecte, acestea conțin coordonatele (CLLocationCoordinate2D) pe care îl căutăm, dar și o măsură pentru acuratețea locației. CLLocation obiectele sunt utilizate în cadrul Core Location și sunt uimitor de utile.

Pentru a afișa rezultatul solicitării noastre pe ecran, apucăm latitudinea și longitudinea locației de locație a locației și o afișăm în eticheta noastră. De asemenea, verificăm dacă matricea de zone de interese a locațiilor nu este goală. Dacă este, atunci luăm primul obiect pe care îl conține (o instanță a lui NSString) și afișați-o în prima noastră etichetă. Dacă nu s-au găsit zone de interes, le spunem utilizatorilor prin afișarea unui mesaj simplu.

Vreau să adaug o singură atingere finală aplicației noastre pentru a îmbunătăți experiența utilizatorului și, de asemenea, să urmeze liniile directoare ale Apple. Atunci când facem o solicitare de codificare geocod, nu primim un răspuns imediat. După cum am menționat mai devreme, cadrul de locație central vorbeste cu un serviciu web și primește un răspuns. Când răspunsul ajunge, depinde de diferiți factori, cum ar fi viteza conexiunii la rețea. Documentația din CLGeocoder afirmă că solicitările către serverele web ar trebui să fie făcute cu ușurință. Cu alte cuvinte, utilizatorul (1) nu ar trebui să facă mai multe solicitări într-un interval scurt de timp atingând butonul de mai multe ori și (2) utilizatorul nu ar trebui să poată face o solicitare înainte ca solicitarea activă să fi returnat un răspuns. Pentru a realiza aceasta din urmă, dezactivați butonul până când cererea este finalizată (cu succes sau fără succes). Pentru a face acest lucru, dezactivați butonul înainte de a face cererea și permiteți din nou butonul în blocul de completare. Aruncați o privire la implementarea completă a serviciilor noastre fetchCoordinates: metoda de clarificare. Rulați aplicația și introduceți o adresă pentru a o pune în pași.

 - (IBAction) fetchCoordonate: (id) expeditor if (! Self.geocoder) self.geocoder = [[CLGeocoder alloc] init];  NSString * adresa = [NSString șirWithFormat: @ "% @% @% @", self.streetField.text, self.cityField.text, self.countryField.text]; self.fetchCoordinatesButton.enabled = NU; [auto.geocoder geocodeAddressString: adresa de completareHandler: ^ (NSArray * marcatori de locație, eroare NSError *) if ([numărul de marcatori]> 0) CLPlacemark * marcator de locație = [locații objectAtIndex: 0]; Locația CLL * location = Locație locație; CLLlocațieCoordinate2D coordinate = location.coordinate; self.coordinatesLabel.text = [NSString șirWithFormat: @ "% f,% f", coordonate.latitude, coordinate.longitude]; dacă ([marcajul.articol.articolar]]> 0) NSString * areaOfInterest = [marcator.articol.articol]; auto.nameLabel.text = areaOfInterest;  self.fetchCoordinatesButton.enabled = DA; ]; 

Am putea face un pas mai departe prin afișarea unui indicator de activitate în timpul solicitării și ascunderea butonului, dar vă las ca pe o provocare. Am adăugat această caracteristică codului sursă care însoțește acest tutorial.


Concluzie

Locația Core a devenit un cadru foarte puternic și CLGeocoder este doar una dintre numeroasele clase care vă ajută să realizați o sarcină complexă cu ușurință și cu puțină cheltuială. se bucura!

Cod