1

I need to get the zipCode and the city in multiple viewControllers.

Here is how I'm currently doing it...

import CoreLocation
let locationManager = CLLocationManager()

class MyViewController: UIViewController, CLLocationManagerDelegate{
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
    }
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)-> Void in
            if error != nil {
                //AlertView to show the ERROR message
            }

            if placemarks!.count > 0 {
                let placemark = placemarks![0]
                self.locationManager.stopUpdatingLocation()
                let zipCode = placemark.postalCode ?? ""
                let city:String = placemark.locality ?? ""

                // Do something with zipCode
                // Do something with city
            }else{
                print("No placemarks found.")
            }
        })
    }

 func someFunction() {
    locationManager.startUpdatingLocation()
 }

Everything works fine but as you can see doing it this way in multiple viewController leads to a lot of code repetition (of course, I'm not showing the whole code).

What would be the most common way to retrieve the zipCode and city from CLLocationManager() in a more practical way from multiple viewControllers?

What I'm thinking is something like...

 MyLocationManager.zipCode() // returns zipCode as a string 
 MyLocationManager.city() // returns city as a string 
fs_tigre
  • 10,650
  • 13
  • 73
  • 146
  • 1
    What if you create a singleton, which keeps track of the user location? Check the following, it might help: https://stackoverflow.com/questions/11513259/ios-cllocationmanager-in-a-separate-class – emrepun Dec 15 '18 at 21:31

2 Answers2

4

The usual thing is to have just one location manager in one persistent place that you can always get to from anywhere, like the app delegate or the root view controller.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Sorry but I'm a little confused, would you mind elaborating a little bit more on your statement `The usual thing is to have just one location manager in one persistent place`? Again sorry but I'm a little confused. – fs_tigre Dec 16 '18 at 00:16
2

I tried to implement a singleton CLLocationManager class, I think you can modify the following class to implement some additional methods.

import Foundation

class LocationSingleton: NSObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
private var latitude = 0.0
private var longitude = 0.0

static let shared = LocationSingleton()

private override init() {
    super.init()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.distanceFilter = kCLLocationAccuracyHundredMeters
    locationManager.requestAlwaysAuthorization() // you might replace this with whenInuse
    locationManager.startUpdatingLocation()
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let location = locations.last {
        latitude = location.coordinate.latitude
        longitude = location.coordinate.longitude
    }
}

private func getLatitude() -> CLLocationDegrees {
    return latitude
}

private func getLongitude() -> CLLocationDegrees {
    return longitude
}

private func zipCode() {
    // I think you can figure way out to implemet this method
}

private func city() {
    // I think you can figure way out to implemet this method
}
}
emrepun
  • 2,496
  • 2
  • 15
  • 33
  • 1
    Thanks a lot for your help, quick question, how are you managing to update location each time you call `LocationSingleton.shared.getLatitude()` and `getLongitude()` methods from other viewControllers? Do you have `locationManager.startUpdatingLocation()` in a public function that you call **right before** you call the `getLatitude()` and `getLongitude()` methods or are you calling `locationManager.startUpdatingLocation()` from inside of each of the `getLatitude()` and `getLongitude()` methods. I'm curious to see how you are doing it. – fs_tigre Dec 16 '18 at 13:27
  • 1
    @-emrepun The main reason for my question above is because the first time I call `LocationSingleton.shared.getLatitude()` I don't get anything until the second call. – fs_tigre Dec 16 '18 at 15:54
  • 1
    Maybe by the time you call the method first time, the location is not updated at all, can you try running it on your phone, walk around a little bit and with some asyncAfter method call the LocationSingleton.shared.getLatitude() method and see if it still does not give anything for the first call. @fs_tigre – emrepun Dec 16 '18 at 16:01
  • 1
    I think the problem is the sequence of how the code runs. For instance, if I call `LocationSingleton.shared.getLatitude()` from one of my viewControllers and log the sequence this is what I see... The first thing that is called of course is the `init` method, then the second is the `getLatitude` and lastly the `locationManager` which is why it doesn't update the first time. – fs_tigre Dec 16 '18 at 16:11
  • 1
    Yeah I see, I will try to come up with a solution and let you know here, also if you can find a simple way to solve that please comment here @fs_tigre – emrepun Dec 16 '18 at 16:49