13

I'm trying to test region monitoring, for that I'm getting current location like this:

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

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

And tracking first location with region monitoring like this:

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

Then in every exit from current region I'm monitoring the new location like this:

- (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];
}

I'll explain what I expect to happen:

  1. Register current location in region monitoring.
  2. Notify user exit current region.
  3. On exit log and register again the current location as region.

This doesn't happen.

Where I'm wrong?

I tried on simulator with 'Freeway Drive'.

UPDATE:

Tested and work, due to Apple bug in geofencing, app will support only 7.1+, pretty bad but I don't have an another idea.

4

2 回答 2

11

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

以下是原因:-

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

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

  2. 我相信你不应该startMonitoringForRegion在委托方法里面-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:。原因是,如果startLocationTracking多次调用,就会有不止一个locationManager。多个 locationManager 可以监控同一区域,这可能会导致多个通知。

  3. 调用后[manager startMonitoringForRegion:region];,不会立即监听该区域。如果您不相信我,请尝试以下代码:-

    [locationManager startMonitoringForRegion:region];
    NSLog(@"%@",locationManager.monitoredRegions);
    

你会发现刚才监控的区域不会在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 中,半径在 1 到 150 米之间的区域在 iPhone 4S 和更新版本的设备上效果更好。)在这些设备上,应用程序可以期望在平均 3 到 5 分钟内收到相应的区域进入或区域退出通知,如果不早点。

注意:只要设备从之前的通知移动 500 米或更远,应用程序就会收到通知。它不应期望通知的频率超过每五分钟一次。如果设备能够从网络检索数据,则位置管理器更有可能及时传递通知。

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

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

您可能还想查看我在一个月前发现的 iOS 7 中的区域监控故障(带有解决故障的解决方法):iOS 7 上的区域监控故障 - 同时多个通知

于 2014-06-17T05:54:17.783 回答
-1

未调用代表方法(didEnterRegion 和 didExitRegion)的最令人满意的答案是,Apple 文档说您将在进入或退出后 3 到 5 分钟后收到通知,但在实际测试中我发现您必须等待大约7到8分钟。

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

此外,如果您想在后台执行此操作,则必须在目标上启用后台模式。 在此处输入图像描述

于 2015-02-04T06:43:39.487 回答