区域监控当前位置在退出时不通知

时间:2014-06-11 14:30:37

标签: ios objective-c core-location cllocationmanager clregion

我正在尝试测试区域监控,因为我正在获得这样的当前位置:

- (void)startLocationTracking
{
    CLLocationManager *locationManager = [[CLLocationManager alloc] init];

    // Start location manager
    if ([CLLocationManager locationServicesEnabled] && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized) {
        locationManager = [LocationTracker sharedLocationManager];
        locationManager.delegate = self;
        [locationManager startMonitoringSignificantLocationChanges];
    }
}

跟踪区域监控的第一个位置,如下所示:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:manager.location.coordinate radius:300 identifier:@"first location initializer"];

        NSLog(@"0: %@", manager.location);
        NSLog(@"1: %@", region);

        [manager startMonitoringForRegion:region];
        NSLog(@"[locationManager startMonitoringForRegion:%@];", region);
    });
}

然后在当前区域的每个出口处,我都在监视新位置:

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"%s, %@", __PRETTY_FUNCTION__, region);
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    NSLog(@"%s, %@", __PRETTY_FUNCTION__, region);

    NSArray *allRegions = manager.monitoredRegions.allObjects;

    if (allRegions.count > 0) {
        for (CLRegion *reg in allRegions) {
            [manager stopMonitoringForRegion:reg];
        }
    }

    CLLocationCoordinate2D cord = CLLocationCoordinate2DMake(manager.location.coordinate.latitude, manager.location.coordinate.longitude);
    CLRegion *regionNew = [[CLRegion alloc] initCircularRegionWithCenter:cord radius:300 identifier:@"new region"];

    NSLog(@"region: %@", region);
    NSLog(@"regionNew: %@", regionNew);

    [manager startMonitoringForRegion:regionNew];
}

我会解释我期望发生的事情:

  1. 在区域监控中注册当前位置。
  2. 通知用户退出当前区域。
  3. 退出日志并再次将当前位置注册为区域。
  4. 这不会发生。

    我哪里错了?

    我尝试使用'Freeway Drive'模拟器。

    更新

    经过测试和工作,由于地理围栏中的Apple漏洞,应用程序仅支持7.1+,非常糟糕,但我没有其他想法。

2 个答案:

答案 0 :(得分:11)

我认为实施区域监控的方式可能会导致一些问题。

原因如下: -

  1. startLocationTracking方法中,您的locationManager是一个本地对象,不会延伸到该方法的生命周期。这也意味着每次调用startLocationTracking时,都会有一个新的locationManager对象被分配一个新的内存块。

    要解决此问题:您应该在应用程序的整个生命周期中使用共享locationManager单例 locationManager

  2. 我认为你不应该在委托方法startMonitoringForRegion-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:。原因是,如果再次调用startLocationTracking一次,则会有多个locationManager。多个locationManagers可以监视可能导致多个通知的同一区域。

  3. 致电[manager startMonitoringForRegion:region];后,我们不会立即监控该地区。如果您不相信我,请尝试以下代码: -

    [locationManager startMonitoringForRegion:region];
    NSLog(@"%@",locationManager.monitoredRegions);
    
  4. 您会发现您刚刚监控的区域不在locationManager.monitoredRegions内。由于这是在iOS级别上处理的,因此,我认为可能需要几分钟时间才能对该区域进行监控。

    您还应该了解iOS中区域监控的其他限制: -

    https://developer.apple.com/library/mac/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html

      

    应用最多可以一次注册20个地区。为了报告   区域变化及时,区域监测服务   需要网络连接。

         

    在iOS 6中,半径在1到400米之间的区域效果更好   在iPhone 4S或更高版本的设备上。 (在iOS 5中,具有半径的区域   在iPhone 4S和更高版本的设备上,1到150米之间的效果会更好。)   在这些设备上,应用程序可以期望接收适当的区域   在3到5分钟内输入或区域退出通知   平均,如果不是更快。

         

    注意:只要设备移动500,应用就会收到通知   距其先前通知的米或更多。不应该期待   通知频率高于每五分钟一次。如果   设备能够从网络中检索位置管理器的数据   更有可能及时发送通知。

    我不知道您的应用是什么,我相信您应该重新设计应用流程。您应该尝试监视委托方法之外的区域。

    有关 Singleton LocationManager 的详细信息,您可以查看以下答案:Background Location Services not working in iOS 7。 GitHub上有一个包含 Singleton LocationManager类的完整项目,我将其命名为 LocationTracker

    您可能还想查看我在一个月前发现的iOS 7中的区域监控故障(解决故障的解决方法):Region Monitoring Glitch on iOS 7 - Multiple Notifications at the same time

答案 1 :(得分:0)

对于代表方法(didEnterRegion和didExitRegion)没有被调用的最满意的答案是,apple docs说你会在进入或退出后3到5分钟得到通知,但在实际测试中我发现的是你必须等待大约7到8分钟。

我测试了10到15次,我的区域半径大约是80米。我正在挠头看看出了什么问题。我打开了模拟器并打开了位置跟踪(使用gpx文件进行位置模拟)。 8分钟后,调用了ExitRegion。

此外,如果您想在后台执行此操作,则必须在目标上启用后台模式。 enter image description here