简体   繁体   中英

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

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.....

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;

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

}

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

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
    });
}

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
}

如果要停止更新位置管理器,请编写此方法

[locationManager stopUpdatingLocation];

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

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?

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()

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM