0

I'm trying to parse a location (CLLocation) into a String.

    func locationToString (currentLocation: CLLocation) -> String? {
    var whatToReturn: String?
    CLGeocoder().reverseGeocodeLocation(currentLocation, completionHandler: { (placemarks: [AnyObject]!, error: NSError!) in
        if error == nil && placemarks.count > 0 {
            let location = placemarks[0] as CLPlacemark
            whatToReturn = "\(location.locality) \(location.thoroughfare) \(location.subThoroughfare)"

        }
    })
    return whatToReturn
}

Obviously, whatToReturn always returns null, because completionHandler runs in the background. I'm having a hard time understanding how do I update my String when completionHandler finishes?

Thanks.

EladB
  • 326
  • 5
  • 15
  • 1
    What is your end goal with the string? This will have to be triggered somewhere in the completion block. – Logan Jan 02 '15 at 23:34
  • I want to use the string (whatToReturn) and patse it into a textField. But, I'm not using this method from the controller itself, so I need a way to update the returned string... – EladB Jan 02 '15 at 23:49
  • The best way to do that is probably to just set your textField's text within the completion block. [See Answer] – Logan Jan 02 '15 at 23:52
  • The best? I'm sure it not. It's the easiest (: – EladB Jan 03 '15 at 00:14

1 Answers1

2

If you want to use your string in a textField, like indicated in your comments, do this:

func getAndDisplayLocationStringForLocation(currentLocation: CLLocation) {
    CLGeocoder().reverseGeocodeLocation(currentLocation, completionHandler: { (placemarks: [AnyObject]!, error: NSError!) in
        if error == nil && placemarks.count > 0 {
            let location = placemarks[0] as CLPlacemark
            self.textField.text = "\(location.locality) \(location.thoroughfare) \(location.subThoroughfare)"

        }
    })
}

However, if you need access elsewhere, perhaps pass a closure as an arg:

func getAndDisplayLocationStringForLocation(currentLocation: CLLocation, withCompletion completion: (string: String?, error?, error: NSError?) -> ()) {
    CLGeocoder().reverseGeocodeLocation(currentLocation, completionHandler: { (placemarks: [AnyObject]!, error: NSError!) in
        if error == nil && placemarks.count > 0 {
            let location = placemarks[0] as CLPlacemark
            completion(string: "\(location.locality) \(location.thoroughfare) \(location.subThoroughfare)", error: nil)

        } else {
            completion(nil, error)
        }
    })
}

Then call like this:

yourModel.getAndDisplayLocationStringForLocation(someLocation) { (string: String?, error: NSError?) -> () in
    if (error == nil) {
        self.textField.text = string
    }
}

You may want to handle error etc. differently. This should be enough to get you started.

Logan
  • 52,262
  • 20
  • 99
  • 128
  • My bad, the error came of another part of my code. Thank you very much! Although, I have to ask, why was is built that way? I mean using reverseGeocodeLocation should be used from the model but completionHandler seems it was meant to be used from the controller. – EladB Jan 03 '15 at 12:27
  • I can't speak for apple, but anytime there's a network operation required, the operation is backgrounded with a completion block to avoid blocking the UI for an indeterminate amount of time. – Logan Jan 03 '15 at 14:34