Search code examples
swiftscopeclosuresclgeocoder

swift variable scope in closure wrt CLGeocoder()


Can someone please help me understand why in the following code will have output like this:

[<+37.49638550,-122.31160280> +/- 5.00m (speed 32.65 mps / course 294.26) @ 7/27/16, 4:34:19 AM Eastern Daylight Time]

n/a Belmont Belmont

Belmont 1

That is, why the variable locality will have value "n/a" when printed at a specific point whereas localityVC & localityGlobal never do? Is this purely a scope issue or something to do with CLGeocoder()? Thanks

import UIKit
import MapKit
import CoreLocation

var localityGlobal: String = "n/a"

class ViewController: UIViewController, CLLocationManagerDelegate {

    let locationManager = CLLocationManager()
    var localityVC: String = "n/a"

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        print("hello")

        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print(locations)

        let userLocation: CLLocation = locations[0]
        var locality: String = "n/a"

        CLGeocoder().reverseGeocodeLocation(userLocation, completionHandler: {(placemarks, error) -> Void in
            if error != nil {
                print("CLGeocoder.reverseGeocodeLocation() failed")
                return
            }
            if placemarks!.count > 0 {
                locality = placemarks![0].locality!
                self.localityVC = placemarks![0].locality!
                localityGlobal = placemarks![0].locality!
                print(locality, placemarks!.count)

            } else {
                print("CLGeocoder.reverseGeocodeLocation() error in geocoder data")
            }
        })

        print(locality, localityVC, localityGlobal)
    }

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

In order for the above to run you also need to have:

  1. Build Phases -> Link Binary with Libraries include CoreLocation.framework,
  2. Info.plist must have variables NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription set,
  3. Simulator -> Debug -> Location set to something like Apple, City Bicycle Ride, City Run or Freeway Drive

I'm running xcode 7.3.1 (7D1014)


Solution

  • This isn't a scope issue, it's a timing one. You get n/a because the closure has yet to run when that print statement is executed.

    The other variables are retaining the value from a prior call.