John Cena
John Cena

Reputation: 127

CLLocationManager is asynchronous. Having problems with this

What I'm doing is very simple.

class HomeDatasourceController: UICollectionViewController, CLLocationManagerDelegate{
let locationManager:CLLocationManager = CLLocationManager()

//CurrentLocation is my variable that isn't changing on time
var currentLocation = CLLocation(latitude: 5.0, longitude: 5.0)

override func viewDidLoad() {
    super.viewDidLoad()


    locationManager.delegate = self
    locationManager.requestAlwaysAuthorization()
    self.locationManager.startUpdatingLocation()


    fetchHomeFeed()
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    for currentLocationTemp in locations {
        self.currentLocation = currentLocationTemp
        print("This is latitude: \(currentLocation.coordinate.latitude) , and this is longitude: \(currentLocation.coordinate.longitude)")
    }
}
fetchHomeFeed(){
    print("Hello: ", self.currentLocation)
}

When fetchHomeFeed gets called, it only prints out the dummy location that I had it set to (5.0 latitude and longitude) and not my actual location. I know this is asynchronous, but I'm not sure how to get the call at least ONCE the first time so I can properly print out my location (the first time).

I also need it to continue updating after this because I want to have a live updated of the user's location.

I've tried having fetchHomeFeed() inside the func locationManager, but this prints out ("Hello: ", self.currentLocation) multiple times, and I only want fetchHomeFeed() being called only ONCE (with a proper location), and after this have the location being called continuously as I will have another method using this.

I'm not sure on how to implement this.

Upvotes: 0

Views: 759

Answers (2)

Paresh Masani
Paresh Masani

Reputation: 7504

Remove fetchHomeFeed from viewDidLoad. It's not right.

Do this in your locationManager function. This will guarantee that you have a valid location. You stop location manager once you got the valid location and restart if required. If you want to continuously monitor the location then you need to rethink the solution but this will give you an idea.

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

        guard let location = locations.last else {
               return
        }

        if location.horizontalAccuracy > 0 {
             locationManager.stopUpdatingLocation()
             locationManager.delegate = nil
             fetchHomeFeed()
        }
    }

Upvotes: 0

shim
shim

Reputation: 10146

From the documentation for didUpdateLocations:

locations

An array of CLLocation objects containing the location data. This array always contains at least one object representing the current location. If updates were deferred or if multiple locations arrived before they could be delivered, the array may contain additional entries. The objects in the array are organized in the order in which they occurred. Therefore, the most recent location update is at the end of the array.

So you do not need to loop through the array of locations, you can just use locations.last unless your application needs to worry about deferred location updates.

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

And if you want fetchHomeFeed to only be called once there are several options, but simplest is a boolean flag that you check before calling it and you change it the first time it is called.

Upvotes: 0

Related Questions