sdouble
sdouble

Reputation: 1095

locationManager didUpdateLocations fires twice on device, only once on simulator

Same code, I'm assuming that the device is actually updating the location twice for some reason, even though I only call startUpdatingLocation() once and I run some stopUpdatingLocations() inside of didUpdateLocations

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    manager.stopUpdatingLocation()
    let loc: CLLocation = locations[locations.count - 1]
    let id = 0
    let type = 0
    let number = 0

    createNewDataPoint(id, loc: loc, type: type, number: number)
}

In this case, createNewDataPoint gets called twice, creating 2 new datapoints. It only happens once in the simulator, so I'm assuming it has something to do with the actual device and the GPS since the simulator fakes its location.

startUpdatingLocation() is only in my code one time, on a button. Basically, you click the button, go go manager.startUpdatingLocations(), didUpdateLocations hits once on simulator, twice on device (identical coordinates) and it creates 2 new data points.

The only other code that mentions anything related is setting the accuracy, filter, authorization requests, and the previously mentioned startUpdatingLocation(). Is there something I can do to make sure I'm not creating twice as many data points as necessary?

Upvotes: 13

Views: 11909

Answers (9)

Massimo Pavanel
Massimo Pavanel

Reputation: 831

Another way is to set a time interval to turn on and off the delegate and so the location manager. A sorta of this

var locationManagerUpdate:Bool = false //Global

func scheduledTimerWithTimeInterval(){
    // Scheduling timer to Call the function "updateCounting" with the interval of 10 seconds

        timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.updateLocationManager), userInfo: nil, repeats: true)

}
@objc func updateLocationManager() {

    if locationManagerUpdate == false {
        locationManager.delegate = self
        locationManagerUpdate = true
    }

}
extension lm_gest: CLLocationManagerDelegate {

// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {


    if locationManagerUpdate == true {
    manager.stopUpdatingLocation()
    manager.delegate = nil
    }
//your code here...
}

Upvotes: 0

iOSAnup
iOSAnup

Reputation: 11

After getting the desired latitude and longitude just call stopUpdatingLocation()and set the delegate to nil.

In Swift 3:

locationManager.stopUpdatingLocation() 
locationManager.delegate = nil

In Objective-C:

[locationManager stopUpdatingLocation]
locationManager.delegate = nil

Here locationManager is the object of CLLocationManager.

Upvotes: 1

Devendra Singh
Devendra Singh

Reputation: 777

locationManager.startUpdatingLocation() fetch location continuously and didUpdateLocations method calls several times, Just set the value for locationManager.distanceFilter value before calling locationManager.startUpdatingLocation().

As I set 200 meters(you can change as your requirement) working fine

    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.distanceFilter = 200
    locationManager.requestWhenInUseAuthorization()
    locationManager.startUpdatingLocation()

Upvotes: 1

SevenJustin
SevenJustin

Reputation: 61

@Zumry Mohamed 's solution is right

i try the code like this:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {

   [self.locationManager stopUpdatingLocation];
   self.locationManager.delegate = nil;
   self.locationManager = nil; 
}

finally this delegate is called only once, i understand now why the problem is occurred, just because manager call the stopUpdatingLocationmethod but system doesn't help us to make the delegate invalid, so we can receive the callback every time location updates due to your desiredAccuracy and distanceFilter property settings of your CLLocationManager, so the final solution is just like what @Zumry Mohamed said, we can manually set the delegate to nil when we stopUpdateLocation. hope it will help you understand what happens why this could solve the problem.

Upvotes: 0

Whirlwind
Whirlwind

Reputation: 13665

Instead of starting / ending the location update and setting delegate to nil, there is a method called requestLocation which is ideal when your application need quick fix on the user's location:

From the docs:

override func viewDidLoad() {
    // Create a location manager object
    self.locationManager = CLLocationManager()

    // Set the delegate
    self.locationManager.delegate = self
}

func getQuickLocationUpdate() {
    // Request location authorization
    self.locationManager.requestWhenInUseAuthorization()

    // Request a location update
    self.locationManager.requestLocation()
    // Note: requestLocation may timeout and produce an error if authorization has not yet been granted by the user
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    // Process the received location update
}

Use this method when you want the user’s current location but do not need to leave location services running.

Upvotes: 0

Zumry Mohamed
Zumry Mohamed

Reputation: 9558

Best solution for iOS 10.0+

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    [locationManager stopUpdatingLocation]; // stop location manager
    locationManager.delegate = nil;
    //Your logics... 
    //This will be called only one time now.
}

But don't forget to set the delegate again.

Upvotes: 6

Andrey M.
Andrey M.

Reputation: 3069

The best way is do as following:

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    manager.stopUpdatingLocation()
    manager.delegate = nil
}

Upvotes: 14

kalpesh
kalpesh

Reputation: 1287

You will not get frequently on simulator. and on device when you will move far away then only you get didUpdateLocations. just move in a open space so GPS can identify you device location so it get best accuracy.

Upvotes: 0

Abhinav
Abhinav

Reputation: 38142

Location Manager delegate methods can be called very frequently and at any time.

You may however, apply following algorithm to safeguard yourself:

  1. Create a global bool say didFindLocation.
  2. Set didFindLocation to false when you call startUpdatingLocation.
  3. Inside delegate call back didUpdateLocations:, if didFindLocation was false, set didFindLocation to true and then call stopUpdatingLocation.

Hope this helps.

Upvotes: 18

Related Questions