How to stop multiple times method calling of didUpdateLocations() in ios
Asked Answered
A

12

31

This my code......

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

    location_updated = [locations lastObject];
    NSLog(@"updated coordinate are %@",location_updated);
    latitude1 = location_updated.coordinate.latitude;
    longitude1 = location_updated.coordinate.longitude;

    self.lblLat.text = [NSString stringWithFormat:@"%f",latitude1];
    self.lblLon.text = [NSString stringWithFormat:@"%f",longitude1];

    NSString *str = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=false",latitude1,longitude1];
    url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    connection = [NSURLConnection connectionWithRequest:request delegate:self];
    if (connection)
    {
        webData1 = [[NSMutableData alloc]init];
    }
        GMSMarker *marker = [[GMSMarker alloc] init];
        marker.position = CLLocationCoordinate2DMake(latitude1,longitude1);
        marker.title = formattedAddress;
        marker.icon = [UIImage imageNamed:@"m2.png"];
        marker.map = mapView_;
        marker.draggable = YES;
 }

This method is call multiple times which i don't want.....

Awesome answered 10/3, 2014 at 5:43 Comment(4)
Then why do you call this method?Overactive
To update location after every five minutes.Awesome
When you first start location services, you may see it called multiple times with increasingly accurate locations (e.g. decreasing horizontalAccuracy). Also set CLLocationManager properties distanceFilter and desiredAccuracy to control how frequently this is called.Few
Swift 3 version of accepted answer https://mcmap.net/q/470321/-swift-how-can-i-make-less-didupdatelocation-callsReveal
P
24

Add some restriction there. For timespan between locations and accuracy

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
 CLLocation *newLocation = locations.lastObject;

 NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
 if (locationAge > 5.0) return;

 if (newLocation.horizontalAccuracy < 0) return;

// Needed to filter cached and too old locations
 //NSLog(@"Location updated to = %@", newLocation);
 CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:_currentLocation.coordinate.latitude longitude:_currentLocation.coordinate.longitude];
 CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];
 double distance = [loc1 distanceFromLocation:loc2];


 if(distance > 20)
 {    
     _currentLocation = newLocation;

     //significant location update

 }

//location updated

}
Pelias answered 10/3, 2014 at 5:46 Comment(4)
It's better to move one line: if(distance > 20) { _currentLocation = newLocation; //significant location update }Trott
@Pelias , thank you but i have a question for the code : if (newLocation.horizontalAccuracy < 0) return; What would you mean?Gluten
Was trying to filter incorrect locations (in that case accuracy is wrong for them)Pelias
How about didFailWithError since there are no updated locations?Platitude
N
43

While allocating your LocationManager object you can set the distanceFilter property of the LocationManager. Distance filter property is a CLLocationDistance value which can be set to notify the location manager about the distance moved in meters. You can set the distance filter as follows:

LocationManager *locationManger = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = 100.0; // Will notify the LocationManager every 100 meters
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
Needless answered 10/3, 2014 at 5:57 Comment(3)
Stops location from updating in the first place where as the selected answer merely stops further handling, so I think this should be the better optionDeepfreeze
excellent answer. I never get how people think that setting a return sttmnt at the beginning of the function solved something....Shearwater
not working for me,, always get 3 updates at the beginningLanilaniard
R
25

The easiest way:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
   [manager stopUpdatingLocation];
    manager.delegate = nil;

   //...... do something

}

The manager can't find your didUpdateLocations method without the delegate reference :-D

But don't forget to set it again before using startUpdatingLocation

Rochester answered 17/6, 2016 at 13:57 Comment(2)
this works perfectly as it only updates the location once on a specific instance of the manager.. thanks!Columbia
why not simply use locationManager.requestLocation() to get location once? stopUpdatingLocation inside didUpdateLocations doesn't make much sense, probably just as a workaround on iOS8 (where .requestLocation() is not available)Hurlee
P
24

Add some restriction there. For timespan between locations and accuracy

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
 CLLocation *newLocation = locations.lastObject;

 NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
 if (locationAge > 5.0) return;

 if (newLocation.horizontalAccuracy < 0) return;

// Needed to filter cached and too old locations
 //NSLog(@"Location updated to = %@", newLocation);
 CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:_currentLocation.coordinate.latitude longitude:_currentLocation.coordinate.longitude];
 CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];
 double distance = [loc1 distanceFromLocation:loc2];


 if(distance > 20)
 {    
     _currentLocation = newLocation;

     //significant location update

 }

//location updated

}
Pelias answered 10/3, 2014 at 5:46 Comment(4)
It's better to move one line: if(distance > 20) { _currentLocation = newLocation; //significant location update }Trott
@Pelias , thank you but i have a question for the code : if (newLocation.horizontalAccuracy < 0) return; What would you mean?Gluten
Was trying to filter incorrect locations (in that case accuracy is wrong for them)Pelias
How about didFailWithError since there are no updated locations?Platitude
P
10

I have similar situation. You can use dispatch_once:

static dispatch_once_t predicate;

- (void)update
{
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
        [_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
        [_locationManager requestWhenInUseAuthorization];
    }

    _locationManager.delegate = self;
    _locationManager.distanceFilter = kCLDistanceFilterNone;
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    predicate = 0;
    [_locationManager startUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    [manager stopUpdatingLocation];
    manager = nil;

    dispatch_once(&predicate, ^{
        //your code here
    });
}
Potman answered 2/10, 2015 at 19:46 Comment(0)
S
3

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()
Sommer answered 19/5, 2017 at 11:25 Comment(1)
i apply this but it call 3 time when start location updateKansu
S
1

You can use a static variable to store the latest location timestamp and then compare it to the newest one, like this:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    [manager stopUpdatingLocation];
    static NSDate *previousLocationTimestamp;

    CLLocation *location = [locations lastObject];
    if (previousLocationTimestamp && [location.timestamp timeIntervalSinceDate:previousLocationTimestamp] < 2.0) {
        NSLog(@"didUpdateLocations GIVE UP");
        return;
    }
    previousLocationTimestamp = location.timestamp;

    NSLog(@"didUpdateLocations GOOD");

    // Do your code here
}
Statfarad answered 10/3, 2016 at 21:34 Comment(2)
suspended mode? What exactly are you trying to do? If you'd like to make sure it will work in background, you should start a UIBackgroundTask. If you'd like to monitor location updates, you should use startMonitoringSignificantLocationChanges.Statfarad
same thing i have done UIBackgroundTask thanks for the replay. :)Arevalo
P
1

Swift 5 :

If you are looking for a solution in swift.

I tried the accepted answer but it didn't work for me. I tried the below solution by checking the time duration between locations. if it is less than 10 seconds then it will return and the location handler will not update.

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else {
            return
        }
        
        let locationAge = -location.timestamp.timeIntervalSinceNow
        if locationAge > 10.0 { //10 seconds
            return
        }
        if location.horizontalAccuracy < 0 {
            return
        }
        
        self.currentLocation = location
        print("Location :- \(location.coordinate)")
        //location updated
    }
Passage answered 1/3, 2022 at 17:13 Comment(0)
B
0

Write this method when ever you want to stop updating location manager

[locationManager stopUpdatingLocation];
Blighter answered 10/3, 2014 at 5:45 Comment(1)
This doesn't necessarily stop all updates see: #14018087Mastin
O
0

for the time constraint, i did not understand code from accepted answer, posting a different approach. as Rob points out "When you first start location services, you may see it called multiple times". the code below acts on the first location, and ignores the updated locations for first 120 seconds. it is one way to address orginal question "How to stop multiple times method calling of didUpdateLocations".

in .h file:

@property(strong,nonatomic) CLLocation* firstLocation;

in .m file:

// is this the first location?
    CLLocation* newLocation = locations.lastObject;
    if (self.firstLocation) {
        // app already has a location
        NSTimeInterval locationAge = [newLocation.timestamp timeIntervalSinceDate:self.firstLocation.timestamp];
        NSLog(@"locationAge: %f",locationAge);
        if (locationAge < 120.0) {  // 120 is in seconds or milliseconds?
            return;
        }
    } else {
        self.firstLocation = newLocation;
    }

    // do something with location
Oversell answered 26/2, 2015 at 6:27 Comment(1)
@kalpesh, i do not know answer to your question, i moved to a different project.Oversell
H
0

You could set a flag (Bool). When you instantiate your locationsManager set flag = true then when locationManager:didUpdateLocations returns inside a code block that you want to run only once set flag = false. This way it will only be run the once.

 if flag == true {
     flag = false
    ...some code probably network call you only want to run the once 
    }

locations manager will be called multiple times but the code you want to execute only once, and I think that is what you are trying to achieve?

Haruspicy answered 21/10, 2015 at 15:50 Comment(0)
W
0

you can write : [manager stopUpdatingLocation]; manager = nil; in didupdatelocation delegate

Wehrle answered 14/2, 2018 at 6:0 Comment(0)
M
0

A few things worked for me:

  • setting location manager nil while didUpdateLocations after calling manager.stopUpdatingLocation()

I will suggest setting the location manager to nil is not a good approach.because CLLocationManager sometimes give accurate location in 3-4 times.

What I will suggest change accuracy to kilometers that's worked for me

    clLocationManager?.distanceFilter = 1000
    clLocationManager?.desiredAccuracy = kCLLocationAccuracyKilometer
Misery answered 12/10, 2022 at 11:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.