2014-06-21 7 views
21

Was ich versuche zu tun, um eine CLLocation an die Funktion getPlacemarkFromLocation geben, die dann die übergebene CLLocation durch reverseGeocodeLocation verwendet die CLPlacemark? zu setzen, die zurückgegeben werden.Swift - CLGeocoder reverseGeocodeLocation completionHandler Schließung

Ich habe Probleme die completionHandler Schließung in reverseGeocodeLocation zu schaffen, es einen Compiler-Fehler/Absturz zu werfen:


In Swift, CLGeocodeCompletionHandler ist CLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Void entsprechend der Dokumentation AnyObject[]! soll enthalten CLPlacemark Objekte wie die Objective-C-Version.

Hier ist mein aktueller Code:

class func getPlacemarkFromLocation(location:CLLocation)->CLPlacemark?{ 
    var g = CLGeocoder() 
    var p:CLPlacemark? 
    g.reverseGeocodeLocation(location, completionHandler: { 
     (placemarks, error) in 
     let pm = placemarks as? CLPlacemark[] 
     if (pm && pm?.count > 0){ 
      p = placemarks[0] as? CLPlacemark 
     } 
    }) 
    return p? 
} 

EDIT: Es scheint, als ob der Fehler mit placemarks.count zu tun hatte mit placemarks nicht wie ein Array behandelt werden. Es kompiliert jetzt aber bin ich nichts anderes als Null, wenn ich versuche p innerhalb der completionHandler einzustellen. Ich habe die CLLocation s überprüft und sie sind gültig.

EDIT 2: Nach placemarks Druck, kann ich bestätigen, dass es Daten zurückgibt. gibt jedoch immer noch Null zurück.

Antwort

20

fand ich die Antwort, die ich in diesem Thread benötigt: Set address string with reverseGeocodeLocation: and return from method

Das Problem mit der Tatsache liegt, dass reverseGeocodeLocation asynchron ist, wird die Methode einen Wert zurückgibt, bevor die completionBlock p in meinem Beispiel setzt.


Wie angefordert, hier ist mein derzeitiger Code.

func showAddViewController(placemark:CLPlacemark){ 
    self.performSegueWithIdentifier("add", sender: placemark) 
} 

func getPlacemarkFromLocation(location: CLLocation){ 
    CLGeocoder().reverseGeocodeLocation(location, completionHandler: 
     {(placemarks, error) in 
      if error {println("reverse geodcode fail: \(error.localizedDescription)")} 
      let pm = placemarks as [CLPlacemark] 
      if pm.count > 0 { self.showAddPinViewController(placemarks[0] as CLPlacemark) } 
    }) 
} 

Ich wollte nicht die NSNotificationCenter Weg nehmen, denn das unnötige Aufwand hinzufügen würde, sondern im Inneren des completionHandler Verschluss ich auf eine andere Funktion aufrufen, und übergeben Sie die CLPlacemark erzeugt durch getPlacemarkFromLocation als Parameter Dinge zu halten, da die asynchrone Funktion wird aufgerufen, nachdem placemarks die Funktion eingestellt ist (sollte) die erforderliche Ortsmarke empfangen und den gewünschten Code ausführen. Hoffe, was ich gesagt habe, macht Sinn.

+0

Können Sie näher erläutern, wie Sie Ihr Problem gelöst haben? Ich habe externe Funktionen und Benachrichtigungen ausprobiert und erhalte immer noch EXC_BAD_ACCESS. Vielen Dank im Voraus, dies würde anderen Entwicklern helfen, zu Swift zu wechseln. – pxpgraphics

+0

Sorry, ich habe diese Syntax verwendet ... 'self! .geocoder.reverseGeocodeLocation (location, completionHandler: {[schwaches Selbst] (Ortsmarken: [AnyObject] !, Fehler: NSError!) -> Void in // Your Code hier }) ' – pxpgraphics

+0

Sicher werde ich diesen Beitrag bearbeiten und meinen aktuellen Code hinzufügen und ein bisschen mehr erarbeiten. – AaronDancer

3

Hier Verschluss, der für mich gearbeitet - es eine Weile, um es nahm zu arbeiten. Ich denke, dein Problem hängt damit zusammen, dass p nicht mit dem richtigen Initialisierer initialisiert wird. Ich habe versucht, ein paar Variationen bis ich dies funktioniert: self.placemark = CLPlacemark (Ortsmarke: stuff [0] als CLPlacemark)

geocoder.reverseGeocodeLocation(newLocation, completionHandler: {(stuff, error)->Void in 

     if error { 
      println("reverse geodcode fail: \(error.localizedDescription)") 
      return 
     } 

     if stuff.count > 0 { 
      self.placemark = CLPlacemark(placemark: stuff[0] as CLPlacemark) 

      self.addressLabel.text = String(format:"%@ %@\n%@ %@ %@\n%@", 
       self.placemark.subThoroughfare ? self.placemark.subThoroughfare : "" , 
       self.placemark.thoroughfare ? self.placemark.thoroughfare : "", 
       self.placemark.locality ? self.placemark.locality : "", 
       self.placemark.postalCode ? self.placemark.postalCode : "", 
       self.placemark.administrativeArea ? self.placemark.administrativeArea : "", 
       self.placemark.country ? self.placemark.country : "") 
     } 
     else { 
      println("No Placemarks!") 
      return 
     } 

     }) 

EDIT:

bewegt bessere Antwort auf seine eigene Antwort.

+0

Es scheint wie 'P' nicht initialisiert ist die Frage, also habe ich 'p = locemarks [0] als geändert? CLPlacemark 'bis' p = CLPlacemark (Ortsmarkierung: Ortsmarken [0] als? CLPlacemark) 'jedoch gibt p immer noch nil zurück. Ich habe versucht, 'p' zu initialisieren, bevor' reverseGeocodeLocation' aufgerufen wird, jedoch bekomme ich EXC_BAD_ACCESS, wenn ich versuche, den Wert zu ändern. Ich kann den 'CLPlacemark (Ortsmarkierung: CLPlacemark?)' Initialisierer vorher nicht benutzen, weil ich keine 'CLPlacemark' habe, um – AaronDancer

0

EDIT: Das funktioniert nicht. Der Wert ist gleich Null außerhalb der Schließung - siehe Kommentare unten

Ihre p Null ist, weil der Verschluss ist die Erfassung, bevor es zu einer Referenz initialisiert wird. Um das gewünschte Verhalten zu erhalten, müssen Sie p einen nicht-optionalen Wert wie var p: CLPlacemark!

Im Folgenden finden Sie Code, den ich verwendet, um meine Vermutung zu testen:

func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) { 
    var g = CLGeocoder() 
    var p:CLPlacemark? 
    let mynil = "empty" 
    g.reverseGeocodeLocation(newLocation, completionHandler: { 
     (placemarks, error) in 
     let pm = placemarks as? CLPlacemark[] 
     if (pm && pm?.count > 0){ 
      // p = CLPlacemark() 
      p = CLPlacemark(placemark: pm?[0] as CLPlacemark) 

      println("Inside what is in p: \(p?.country ? p?.country : mynil)") 

     } 

     }) 

    println("Outside what is in p: \(p?.country ? p?.country : mynil)") 

} 

Hier wird Konsolenprotokoll:

Pushit < - Taste gedrückt Ort beginnen Erfassung
Außerhalb was ist in p: empty
im Inneren, was ist in T: Vereinigte Staaten
Außerhalb was in p: empty
innen, was in p: United States
Außerhalb was ist in p: leer ...

+0

zu geben. Ich habe das auch probiert, aber ich bekomme EXC_BAD_ACCESS dabei. – AaronDancer

+0

Ich habe es noch einmal versucht, ich erhalte das gleiche Ergebnis wie oben bei Verwendung eines nicht-optionalen Wertes. – AaronDancer

+0

Verschlüsse für Swift scheinen nicht so zu funktionieren, wie ich es erwarten würde. Die einzige Möglichkeit, den inneren Wert zu erhalten, um außerhalb des Abschlusses zu bleiben, ist, wenn die Ortsmarkierung eine Mitgliedsvariable des Controllers war. Es würde wahrscheinlich mit statischen/Klassenvariablen funktionieren, wenn sie schnell unterstützt werden (anscheinend nicht in der Beta verfügbar). Hinweis: Ich habe sogar versucht, ein lokales Array zu verwenden, das außerhalb des Abschlusses initialisiert wurde. Ich habe die Ortsmarkierung zum Array im Abschluss hinzugefügt (angehängt). Aber außerhalb der Schließung war die Anordnung immer noch angestellt. – JohnInSea

15

Mit diesen Zeilen von Swift, können Sie sich ganz Standort der Adresse ausdrucken:

func getLocationAddress(location:CLLocation) { 
    var geocoder = CLGeocoder() 

    println("-> Finding user address...") 

    geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error)->Void in 
     var placemark:CLPlacemark! 

     if error == nil && placemarks.count > 0 { 
      placemark = placemarks[0] as CLPlacemark 

      var addressString : String = "" 
      if placemark.ISOcountryCode == "TW" /*Address Format in Chinese*/ { 
       if placemark.country != nil { 
        addressString = placemark.country 
       } 
       if placemark.subAdministrativeArea != nil { 
        addressString = addressString + placemark.subAdministrativeArea + ", " 
       } 
       if placemark.postalCode != nil { 
        addressString = addressString + placemark.postalCode + " " 
       } 
       if placemark.locality != nil { 
        addressString = addressString + placemark.locality 
       } 
       if placemark.thoroughfare != nil { 
        addressString = addressString + placemark.thoroughfare 
       } 
       if placemark.subThoroughfare != nil { 
        addressString = addressString + placemark.subThoroughfare 
       } 
      } else { 
       if placemark.subThoroughfare != nil { 
        addressString = placemark.subThoroughfare + " " 
       } 
       if placemark.thoroughfare != nil { 
        addressString = addressString + placemark.thoroughfare + ", " 
       } 
       if placemark.postalCode != nil { 
        addressString = addressString + placemark.postalCode + " " 
       } 
       if placemark.locality != nil { 
        addressString = addressString + placemark.locality + ", " 
       } 
       if placemark.administrativeArea != nil { 
        addressString = addressString + placemark.administrativeArea + " " 
       } 
       if placemark.country != nil { 
        addressString = addressString + placemark.country 
       } 
      } 

      println(addressString) 
     } 
    }) 
} 

Prost!

-2

Ihre Sachen funktionieren aus mehreren Gründen nicht. Hier ist der Teil, den ich ohne tatsächlich Blick auf die Funktionalität festgelegt:

class func getPlacemarkFromLocation(location:CLLocation)->CLPlacemark?{ 
    var g = CLGeocoder() 
    var p:CLPlacemark? 
    g.reverseGeocodeLocation(location, completionHandler: { 
     (placemarks, error) in 
     let pm = placemarks! 
     if (pm.count > 0){ 
      p = placemarks![0] 
     } 
    }) 
    return p 
} 
+0

Dies gibt immer noch nil zurück - Sie erkennen nicht, dass p gesetzt ist, nachdem Sie den Wert zurückgegeben haben, da reverseGeocodeLocation async funktioniert – SomaMan

0

Bit spät zu dieser Party, aber es sieht aus wie Sie (ed) benötigen einige Boden-up Lesen über async Sachen zu tun. Das sagend, hast du es wahrscheinlich inzwischen gelernt.

Das grundlegende Problem mit Ihrem Code ist, dass p (Ihre Ortsmarke) gesetzt wird, nachdem die Funktion zurückgibt, so dass es verloren ist - Sie können eine Funktion nicht verwenden, um einen Wert mit async zurückzugeben. Mit Abschlussabschluss wird Ihrem Code die Ortsmarke übergeben, wenn er (asynchron) eintrifft & der Abschluss wird aufgerufen - beachten Sie, dass die Funktion jetzt nichts zurückgibt.

func getPlacemarkFromLocation(_ location: CLLocation, completion: ((CLPlacemark?) ->())) { 

    CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in 
     // use optional chaining to safely return a value or nil 
     // also using .first rather than checking the count & getting placemarks[0] - 
     // if the count is zero, will just give you nil 
     // probably a good idea to check for errors too 
     completion(placemarks?.first) 
    }) 
} 

Gebrauch -

getPlacemarkFromLocation(myLocation, completion: { (placemark) in 
    // do something with the placemark here 
}) 

ich das nicht eigentlich habe in Xcode setzen, aber es sieht recht ...

Verwandte Themen