区域监控(Geofencing)耗尽电池(iOS)

时间:2016-02-04 18:38:33

标签: ios objective-c iphone cocoa-touch cllocationmanager

我在我的应用程序中实现了CLLocationManager的区域监控功能,它可以工作,但它会杀死我的电池:

-

Image

-

它应该是那样吗?

我的代码:

monitorLocationViewController.m (请滚动查看完整代码):

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    //If "allStores"(NSMutableArray) isn't nil - calling "locationChangeHandler" to update monitoring
    if (self.allStores!=nil) {
        [self locationChangeHandler];
    }

    CLLocation *currentLocation=(CLLocation*)[locations lastObject];
    NSSet *monitoredRegionsSet=self.locationManager.monitoredRegions;
    [monitoredRegionsSet enumerateObjectsUsingBlock:^(CLCircularRegion *region, BOOL *stop) {
        if ([region containsCoordinate:currentLocation.coordinate]) {
            [self.locationManager stopMonitoringForRegion:region];
            [self locationManager:self.locationManager didEnterRegion:region];
        }
    }];
}

-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
     Store *store=[self storeForRegion:region];
    if (store.alreadySendNotification==NO) {
        UILocalNotification *notification=[[UILocalNotification alloc] init];
        notification.alertTitle=@"Arounder";
        notification.alertBody=[[self storeForRegion:region] address];
        [[UIApplication sharedApplication] scheduleLocalNotification:notification];

        store.alreadySendNotification=YES;
    }
}

    //For updating monitoring
-(void)locationChangeHandler
{
//If "allStores"(NSMutableArray) isn't nil
    if (self.allStores!=nil) {
        //Finding the 20 closest stores to he user's location and adding it to "twentyClosestStores"(NSMutableArray)
        [self sortClosestStores];
        //Stop monitoring "previousTwentyStores"(NSMutableArray) (20 closest stores before user's location  updated)
        [self stopMonitoringStores];
        //Start monitoring "twentyClosestStores"(NSMutableArray)
        [self startMonitoringClosestStores];
    }
}

//Start monitoring "twentyClosestStores"(NSMutableArray)
-(void)startMonitoringClosestStores
{
    //If monitoring isn't availible for "CLCircularRegion"
    if (![CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) {
        NSLog(@"Monitoring is not available for CLCircularRegion class");
        return;
    }

    //Run on all "twentyClosestStores"(NSMutableArray)'s objects
    for (Store *currentStore in self.twentyClosestStores) {
        //Start monitoring "region"(CLCircularRegion)
        [self.locationManager startMonitoringForRegion:currentStore.circularRegion];
    }
}

//Stop monitoring "previousTwentyStores"(NSMutableArray) (20 closest stores before user's location  updated)
-(void)stopMonitoringStores
{
    //Run on all "monitoredRegions"(NSSet) of "locationManager"(CLLocationManager) objects
    for (CLCircularRegion *currentRegion in self.locationManager.monitoredRegions) {
        //Stop monitoring "region"(CLCircularRegion)
        [self.locationManager stopMonitoringForRegion:currentRegion];
    }
}

//Finding a store for region
-(Store*)storeForRegion:(CLCircularRegion*)region
{
    //Run on all "allStores"(NSMutableArray)'s objects
    for (Store *currentStore in self.allStores) {
        //If "currentStore"(Store)'s "circularRegion"'s identifier is equal to "region"(CLCircularRegion)'s identifier
        if ([currentStore.circularRegion.identifier isEqualToString:region.identifier]) {
            //Returning "currentStore"(Store)
            return currentStore;
        }
    }
    //Store not found - returning nil
    NSLog(@"No store found for this region: %f,%f",region.center.latitude,region.center.longitude);
    return nil;
}

AppDelegate.m

-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.monitorLocationVC=[[monitorLocationViewController alloc] init];
    self.monitorLocationVC.locationManager=self.locationManager;

    [self configureLocationManager];
    [self.locationManager startUpdatingLocation];

    return YES;
}

-(void)configureLocationManager
{
    //Initializing locationManager
    self.locationManager=[[CLLocationManager alloc] init];
    //setting "locationManager"'s(CLLocationManager) delegate to "self"
    self.locationManager.delegate=self.monitorLocationVC;
    //Setting "locationManager"'s(CLLocationManager)'s distance filter to none
    self.locationManager.distanceFilter=kCLDistanceFilterNone;
    //Setting "locationManager"'s(CLLocationManager)'s activityType to navigation
    self.locationManager.activityType=CLActivityTypeAutomotiveNavigation;
    //setting "locationManager"'s(CLLocationManager) desiredAccuracy to "best"
    self.locationManager.desiredAccuracy=kCLLocationAccuracyBestForNavigation;

    self.locationManager.pausesLocationUpdatesAutomatically=NO;

    //If OS version is 9 or above - setting "allowsBackgroundLocationUpdates" to YES
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
        self.locationManager.allowsBackgroundLocationUpdates = YES;
    }
}

谢谢!

1 个答案:

答案 0 :(得分:2)

您只想监控区域,而不是在后台不断更新其位置。

试试这个:

self.locationManager.desiredAccuracy=kCLLocationAccuracyBest;

你真的需要将distanceFilter设置为kCLDistanceFilterNone吗?这将导致使用更多的电池电量。您可能想尝试将其设置为大约10米,20米,50米甚至100米。

此外,为了不经常更新位置,而不是:

[self.locationManager startUpdatingLocation];

尝试使用:

[self.locationManager startMonitoringSignificantLocationChanges];

所有这些都应该有助于减少电池使用量。当您将精度和距离滤波器设置为尽可能高的设置时,电池将会耗尽。

修改 由于您的应用程序的目的,无论您做什么,都会耗费大量电池。我之前遇到的类似问题的解决方案是使用NSTimer创建算法或公式,每隔x分钟触发一次以更新用户的位置。 (但只有在移动了x米时才更新区域)。

  • 停止触发NSTimer之间的位置更新,以便您不会不断更新位置。
  • 当计时器触发时,恢复位置更新,抓住大约10个位置(这样你得到一个准确的位置),然后关闭位置更新,直到下次定时器被解雇