1

I have a simple button, when I press the button, I'm making a call to another class, my Location class to get the user's current location. After getting the location, I want to update a label text I have to show the location.

This is my location class:

class LocationManager: NSObject, CLLocationManagerDelegate {

var locationManager: CLLocationManager!
var geoCoder = CLGeocoder()

var userAddress: String?

override init() {
    super.init()
    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.activityType = .other
    locationManager.requestWhenInUseAuthorization()
}

func getUserLocation(completion: @escaping(_ result: String) -> ()){
    if CLLocationManager.locationServicesEnabled(){
        locationManager.requestLocation()
    }
    guard let myResult = self.userAddress else { return }
    completion(myResult)

}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
    let userLocation: CLLocation = locations[0] as CLLocation
    geoCoder.reverseGeocodeLocation(userLocation) { (placemarks, err) in
        if let place = placemarks?.last{
            self.userAddress = place.name!
        }
    }
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print(error)
}
}

and this is where I call the method and updating the label:

func handleEnter() {
    mView.inLabel.isHidden = false
    location.getUserLocation { (theAddress) in
        print(theAddress)
        self.mView.inLabel.text = "\(theAddress)"
    }
}

My problem is that when I click my button (and firing handleEnter()), nothing happens, like it won't register the tap. only after tapping it the second time, I get the address and the labels update's. I tried to add printing and to use breakpoint to see if the first tap registers, and it does. I know the location may take a few seconds to return an answer with the address and I waited, but still, nothing, only after the second tap it shows.

It seems like in the first tap, It just didn't get the address yet. How can I "notify" when I got the address and just then try to update the label?

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
John Doah
  • 1,839
  • 7
  • 25
  • 46
  • First of all why do you expect a result even if `locationServicesEnabled` is false? The problem is that `requestLocation()` is not synchronous, and it doesn't return anything. The response of the location request is returned asynchronously in `didUpdateLocations` and `reverseGeocodeLocation` is asynchronous, too. – vadian Jun 21 '19 at 20:03
  • While it's absolutely not correct, I think if you wait for like 10 seconds then the label will be updated. Your setup is similar to [Why does it take such a long time for UI to be updated from background thread?](https://stackoverflow.com/questions/44931759/why-does-it-take-such-a-long-time-for-ui-to-be-updated-from-background-thread) – mfaani Jun 21 '19 at 20:39

1 Answers1

1

Since didUpdateLocations & reverseGeocodeLocation methods are called asynchronously, this guard may return as of nil address

guard let myResult = self.userAddress else { return }
completion(myResult)

Which won't trigger the completion needed to update the label , instead you need

var callBack:((String)->())? 

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
    let userLocation: CLLocation = locations[0] as CLLocation
    geoCoder.reverseGeocodeLocation(userLocation) { (placemarks, err) in
        if let place = placemarks?.last{
           callBack?(place.name!)
        }
    }
}

Then use

location.callBack = { [weak self] str in
   print(str)
   DispatchQueue.main.async { // reverseGeocodeLocation callback is in a background thread 
    // any ui 
   }
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • Yep, I just edited my OP, that's what I was thinking, how can I solve that? I don't mind waiting a few seconds before updating, but it needs to be on one tap. – John Doah Jun 21 '19 at 20:04