Region Monitoring method getting called multiple t

2019-07-23 06:33发布

I have created multiple geo-fence to monitor region entry/exit events.

I have created a location manager in AppDelegate.h file.

@interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>

@property (strong, nonatomic) UIWindow *window;

@property(nonatomic,retain)CLLocationManager *locationManager;
@property(nonatomic,retain)CLLocation *currentLocation;

+(AppDelegate *)sharedDelegate;

AppDelegate.m file

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];

    if (notification) {
        NSLog(@"AppDelegate didFinishLaunchingWithOptions");
        application.applicationIconBadgeNumber = 0;
    }
    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
    {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
        [application registerUserNotificationSettings:settings];
    }
    else // iOS 7 or earlier
    {
        UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
        [application registerForRemoteNotificationTypes:myTypes];
    }
    if (!self.locationManager)
    {
        self.locationManager = [[CLLocationManager alloc] init];
    }
    self.locationManager.delegate = self;
    //locationManager.distanceFilter = kCLDistanceFilterNone;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    self.locationManager.distanceFilter = 2.0f;
    self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
    {
        [self.locationManager requestAlwaysAuthorization];
    }

    if ([self.locationManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)])
    {
        self.locationManager.allowsBackgroundLocationUpdates  = YES;
    }
    if ([self.locationManager respondsToSelector:@selector(pausesLocationUpdatesAutomatically)])
    {
        self.locationManager.pausesLocationUpdatesAutomatically= NO;
    }

    [self.locationManager stopMonitoringSignificantLocationChanges];

    if ([CLLocationManager locationServicesEnabled] && [CLLocationManager authorizationStatus] != kCLAuthorizationStatusDenied)
    {
        [self.locationManager startUpdatingLocation];
    }
        // Override point for customization after application launch.
    return YES;
}

-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
    NSLog(@"Started monitoring %@ region",region.identifier);
}

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    NSLog(@"%@",[locations description]);
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    dispatch_async(dispatch_get_main_queue(), ^{
    if ([[UIApplication sharedApplication] applicationState]==UIApplicationStateBackground || [[UIApplication sharedApplication] applicationState]==UIApplicationStateInactive)
    {
        UILocalNotification *localnotification = [[UILocalNotification alloc]init];
        localnotification.fireDate=[NSDate dateWithTimeIntervalSinceNow:1];
        localnotification.alertBody=@"You are enter in region.";
        localnotification.timeZone=[NSTimeZone defaultTimeZone];
        localnotification.repeatInterval = 0;
        localnotification.hasAction=YES;
        [[UIApplication sharedApplication]scheduleLocalNotification:localnotification];
    }
    else
    {
        [[[UIAlertView alloc]initWithTitle:@"message" message:@"Enter into region." delegate:self cancelButtonTitle:nil otherButtonTitles:@"Ok ", nil] show];
    }
    });
}

-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
     dispatch_async(dispatch_get_main_queue(), ^{
    if ([[UIApplication sharedApplication] applicationState]==UIApplicationStateBackground || [[UIApplication sharedApplication] applicationState]==UIApplicationStateInactive)
    {
        UILocalNotification *localnotificationExit = [[UILocalNotification alloc]init];
        localnotificationExit.fireDate=[NSDate dateWithTimeIntervalSinceNow:1];
        localnotificationExit.alertBody=@"You are exit from region.";
        NSLog(@"Exit from region.");
        localnotificationExit.timeZone=[NSTimeZone defaultTimeZone];
        localnotificationExit.repeatInterval = 0;
        localnotificationExit.hasAction=YES;
        [[UIApplication sharedApplication]scheduleLocalNotification:localnotificationExit];
    }
    else
    {
        [[[UIAlertView alloc]initWithTitle:@"message" message:@"Exit from region." delegate:self cancelButtonTitle:nil otherButtonTitles:@"Ok ", nil] show];
    }
     });
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"didFailWithError: %@", error);
    [[[UIAlertView alloc] initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
}

This things are to manage the region monitoring.

Now my view controller are adding the regions for monitoring.

-(void)AddRegionsInGeoFence
{
    NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];

    //----1
    CLLocationCoordinate2D centerCoordinate1 = CLLocationCoordinate2DMake(23.046518, 72.543337);
    CLCircularRegion *region1 =[[CLCircularRegion alloc] initWithCenter:centerCoordinate1 radius:200 identifier:@"Location First"];
    NSLog(@"%@",[region1 description]);
    region1.notifyOnEntry=YES;
    region1.notifyOnExit=YES;

    if (![standardDefaults boolForKey:@"EnterRegion"])
    {
        [[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region1];
        NSLog(@"Started Monitoring- %@", [region1 description]);
    }
    [self.mapview setShowsUserLocation:YES];
    [self.mapview setUserTrackingMode:MKUserTrackingModeFollow animated:YES];


    //----2
    CLLocationCoordinate2D centercoordinate2=CLLocationCoordinate2DMake(23.064381, 72.531181);
    CLCircularRegion *region2=[[CLCircularRegion alloc]initWithCenter:centercoordinate2 radius:200 identifier:@"Location Second"];
    NSLog(@"%@",[region2 description]);
    region2.notifyOnEntry=YES;
    region2.notifyOnExit=YES;

    if (![standardDefaults boolForKey:@"EnterRegion"])
    {
        [[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region2];
        NSLog(@"Started Monitoring- %@", [region2 description]);
    }        

    //----3
    CLLocationCoordinate2D centercoordinate3=CLLocationCoordinate2DMake(23.083583,72.546441);
    CLCircularRegion *region3=[[CLCircularRegion alloc]initWithCenter:centercoordinate3 radius:200 identifier:@"Location Third"];
    NSLog(@"%@",[region3 description]);
    region3.notifyOnEntry=YES;
    region3.notifyOnExit=YES;
    if (![standardDefaults boolForKey:@"EnterRegion"])
    {
        [[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region3];
        NSLog(@"Started Monitoring- %@", [region3 description]);
    }


    //4
    CLLocationCoordinate2D centercoordinate4=CLLocationCoordinate2DMake(23.122255, 72.584499);
    CLCircularRegion *region4=[[CLCircularRegion alloc]initWithCenter:centercoordinate4 radius:500 identifier:@"Location Fourth"];
    NSLog(@"%@",[region4 description]);

    region4.notifyOnEntry=YES;
    region4.notifyOnExit=YES;

    if (![standardDefaults boolForKey:@"EnterRegion"])
    {
        [[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region4];
        NSLog(@"Started Monitoring- %@", [region4 description]);
        [standardDefaults setBool:YES forKey:@"EnterRegion"];
        [standardDefaults synchronize];
    }
}

My Problem is region monitoring methods are called multiple times even if I am not moving in side the region itself. Everything else is working fine, Accuracy buffer is around 50-80 meters that is fine for me.

-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region

Also if I am turning off Wi-Fi then it's calling up these methods back to back saying exit from region and enter in to region. As far as I know GPS accuracy is depends on Wi-Fi.

Any help would be highly appreciated.

1条回答
The star\"
2楼-- · 2019-07-23 07:08

a Possible workaround in the interim while the apple bug gets fixed is to rate limit the callback; thereby not acting on all the callbacks but limiting the rate at which the callbacks can get processed.

Callback execution portions that happen before the time period expires get ignored.

Here is and example code that could assist, not tested: The rate is limited to 2 seconds.

-(void)methodRateLimit {

    @synchronized(self) {
        // rate limit begin
        static NSDate *lastTimeExit = nil;

        if (!lastTimeExit) {
            lastTimeExit = [NSDate distantPast]; // way back in time
        }

        NSDate *now = [NSDate date];
        if ([now timeIntervalSinceDate:lastTimeExit] > 2) {
            // do work here
            NSLog(@"Executing");
            lastTimeExit = now;
        } else {
            NSLog(@"Limiting");
        }
    }
}
查看更多
登录 后发表回答