I have a function locationManager that prints out zipCode but everytime I change this function to return a String or implement a completion block, the postal code no longer gets assigned a value. Can someone show how to make this function return a zipCode. I think I have to use async or Concurrency not sure though
import CoreLocation
import CoreLocationUI
class locationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
@Published var location: CLLocationCoordinate2D?
let manager = CLLocationManager()
let geocoder = CLGeocoder()
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
manager.startUpdatingLocation()
}
func requestLocation() {
manager.requestAlwaysAuthorization()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
if error == nil {
if let placemark = placemarks?.first {
if let postalCode = placemark.postalCode {
print(postalCode)
}
}
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error getting location: \(error)")
}
func status(){
switch manager.authorizationStatus {
case .authorizedWhenInUse:
print("")
case .authorizedAlways:
locationManager(CLLocationManager(), didUpdateLocations: [CLLocation()])
case .denied:
print("")
case .notDetermined:
print("")
case .restricted:
print("")
@unknown default:
print("")
}
}
}
CodePudding user response:
You can't change a delegate method's signature. This is why your attempt to change didUpdateLocations
to return a value or have a completion handler results in it not working.
If you want to provide a way for a user of your locationManager
class (please rename the class to LocationManager
- class names should start with uppercase letters) then you should add a completion property or add a completion parameter to the requestLocation
function. Then your didUpdateLocations
can call that completion handler passing back the zip code.
Also note that a lot of your location manager code is wrong and needs to be fixed. You should never be attempting to directly call the delegate method yourself. See the following answer for a full example of properly setting up and using CLLocationManager
to get a user's current location. I've adapted that code to fit your use case.
The following code assumes the user of your LocationManager
class will call requestLocation
each time it wants to get the zip code of the user's current location.
import CoreLocation
class LocationManager: NSObject {
private var manager: CLLocationManager?
private var completion: ((String?) -> Void)?
override init() {
super.init()
}
func requestLocation(completion: @escaping (String?) -> Void) {
self.completion = completion
manager = CLLocationManager()
manager?.delegate = self
manager?.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
}
}
extension LocationManager : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Only handle location that is within the desired 10 meters
if let location = locations.first(where: { $0.horizontalAccuracy <= manager.desiredAccuracy }) {
manager.stopUpdatingLocation()
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
var postalCode: String?
if error == nil {
if let placemark = placemarks?.first {
postalCode = placemark.postalCode
}
}
self.completion?(postalCode)
self.completion = nil
self.manager = nil
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error getting location: \(error)")
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .authorizedWhenInUse, .authorizedAlways:
manager.startUpdatingLocation()
case .denied:
print("Denied")
case .notDetermined:
manager.requestWhenInUseAuthorization()
case .restricted:
print("Restriced")
@unknown default:
print("Unexpected")
}
}
}
Sample usage:
let manager = LocationManager()
manager.requestLocation() { zipCode in
if let zipCode {
print("We got a zip code: \(zipCode)")
}
}