2

I'm a newbie in Swift and I need to set var postalCode in viewDidLoad(). As you can see on my code below, I used the reverse geocode location in didUpdateLocations but since it's asynchronous, the postalCode variable is not set in viewDidLoad(). How can I do this?

ViewController.swift

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    let locationManager = CLLocationManager()
    var postalCode = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
        println("Postal code is: \(self.postalCode)")
    }

    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)-> Void in
            if error != nil {
                println("Reverse geocoder failed with error: \(error.localizedDescription)")
                return
            }

            if placemarks.count > 0 {
                let placemark = placemarks[0] as! CLPlacemark
                self.locationManager.stopUpdatingLocation()
                self.postalCode = (placemark.postalCode != nil) ? placemark.postalCode : ""
                println("Postal code updated to: \(self.postalCode)")
            }else{
                println("No placemarks found.")
            }
        })
    }

    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
        println("Location manager error: \(error.localizedDescription)")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}
Esthon Wood
  • 315
  • 3
  • 19

2 Answers2

1

@MirekE is correct. Your -viewDidLoad method does not wait for the location manager to finish updating, and then for the geocoder to finish geocoding. It's logging the message Postal code is: before the value of postalCode is set.

Solution:

Move whatever code you need to into a custom didSet trigger on postalCode:

var postalCode:String! = "" {
    didSet {
        println("Postal code is: \(self.postalCode)")
        // and whatever other code you need here.
    }
};
jperl
  • 1,066
  • 7
  • 14
  • thanks! I've tried it out and it works. As I have mentioned to MirekE above, I need to set the `postalCode` in `viewDidLoad()` because I'm going to pass it as part of a URL which I'm going to display in a UIWebView of the ViewController. I'll load the web view in the `didSet` and see what happens. – Esthon Wood Jun 28 '15 at 06:28
0

There are two consecutive async operations, actually. First the location update and then geocode. You don't want to wait for the results in viewDidLoad(), because it would make bad user experience and possibly iOS would even evict the app from memory as unresponsive.

Change the app logic so that you use the ZIP when it becomes available. For example, if you want to show the ZIP in the UI, leave it blank on start and update it from the reverseGeocodeLocation completion handler. It will appear as soon as it becomes available.

MirekE
  • 11,515
  • 5
  • 35
  • 28
  • the reason why I need to set the `postalCode` in `viewDidLoad()` is because I'm going to pass it as part of a URL which I'm going to display in a `UIWebView` of the ViewController. I haven't gone so far as setting up the UIWebView since I got stuck with the postalCode. – Esthon Wood Jun 28 '15 at 06:25