didEnterRegion在前台工作,但不在后台或其他VC工作

ari*_*old 7 cllocationmanager ios region-management clregion

如果应用程序正在运行且CLLocationManagerDelegate类是前台(即可见),则didEnterRegions触发,我同时获得NSLog以及AlertView.但是,当应用程序在后台时,或者基本上,如果屏幕显示除委托类之外的任何内容,我什么也得不到.

我已经在plist中的"Required background modes"下设置了"App registers for location updates",虽然我不确定是否有必要.

这是我认为相关的代码,虽然我可能是错的(并乐意添加更多).我应该注意viewDidLoad中的所有内容都包含在if中,检查区域监视是否可用并启用.

- (void)viewDidLoad
{
    NSLog(@"MapViewController - viewDidLoad");
    self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
    self.locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters;    
    self.locationManager.delegate = self;
    [self.locationManager startMonitoringSignificantLocationChanges];
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"MapViewController - didEnterRegion");
    NSLog(@"MVC - didEnterRegion - region.radius = %f", region.radius);
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"entered region..." message:@"You have Entered the Location." delegate:nil cancelButtonTitle:@"OK"  otherButtonTitles: nil];
    alert.tag = 2;
    [alert show];
}
Run Code Online (Sandbox Code Playgroud)

这是我在AppDelegate.m中获取受监控区域列表的位置:

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

// other code

NSLog(@"LISTING ALL REGIONS MONITORED");
    NSArray *regions = [self.locationManager.monitoredRegions allObjects];
    if (!regions) {
        NSLog(@"no regions found");
    } else {
        NSLog(@"got %d monitored regions", [regions count]);
        for (int i = 0; i < [regions count]; i++) {
            CLRegion *region = [regions objectAtIndex:i];
            NSLog(@"region %d's identifier = %@", i, region.identifier);
            NSLog(@"region: radius: %@", region.radius);
        }
    }

// other code
}
Run Code Online (Sandbox Code Playgroud)

我两次调用startMonitoringForRegion,这里是主要的地方:

- (void)doneButtonTapped {
    NSLog(@"doneButtonTapped");

    if (self.locationIdentifier) {
        if ([CLLocationManager regionMonitoringEnabled] && [CLLocationManager regionMonitoringAvailable]) {

            // core data setup
            NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
            NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"LocationReminder" inManagedObjectContext:self.managedObjectContext];
            fetchRequest.entity = entityDescription;
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"locationIdentifier == %@", self.locationIdentifier];
            fetchRequest.predicate = predicate;
            NSError *error;
            NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
            if (results) {

                // get the LocationReminder
                LocationReminder *retrievedReminder = [results objectAtIndex:0];
                retrievedReminder.audioURI = [[[self.audioPlayers objectAtIndex:self.selectedCell] url] absoluteString];
                retrievedReminder.userRecording = nil;

                // start monitoring it's region
                NSArray *coordinateArray = [retrievedReminder.locationIdentifier componentsSeparatedByString:@", "];
                CLLocationCoordinate2D coordinate = {[[coordinateArray objectAtIndex:0] doubleValue], [[coordinateArray objectAtIndex:1] doubleValue]};
                CLRegion *newRegion = [[CLRegion alloc] initCircularRegionWithCenter:coordinate radius:250.0 identifier:retrievedReminder.locationIdentifier];
                NSLog(@"about to monitor region with radius: %f", newRegion.radius);
                [self.locationManager startMonitoringForRegion:newRegion desiredAccuracy:kCLLocationAccuracyBest];

                // save the LocationReminder
                if (![self.managedObjectContext save:&error]) {
                    NSLog(@"hmm.  no managed object context.  must be something space-time going on");
                } else {
                    NSLog(@"saved locationReminder, locationIdentifier = %@", retrievedReminder.locationIdentifier);
                }
            } else {
                NSLog(@"ERROR: no LocationReminder retreived for predicate: %@", predicate);
            }
        }

        // get the mapview controller off of the navigation stack
        for (UIViewController *viewController in self.navigationController.viewControllers) {
            if ([viewController isKindOfClass:[MapViewController class]]) { 
                MapViewController *mapVC = (MapViewController *)viewController;
                mapVC.audioURI = [[[self.audioPlayers objectAtIndex:self.selectedCell] url] absoluteString];
                [self.navigationController popToViewController:mapVC animated:YES];
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

因为我觉得它可能很重要,这里是locationManager的getter:

- (CLLocationManager *)locationManager {
    NSLog(@"MapViewController - locationManager");
    if (_locationManager) {
        return _locationManager;
    } else {
        _locationManager = [[CLLocationManager alloc] init];
        return _locationManager;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新1:通过Apple论坛(我转发的地方),有人提到AlertView只会在前台显示.NSLog还没有开火.我认为应该工作.

Bil*_*ess 2

我的一个朋友写了一篇关于使用地理围栏的很好的教程,可能有助于解决您遇到的一些问题。

开始使用地理围栏

网上和这里都有很多例子。从小事做起,逐步向上。一旦开始获取回调,您就可以开始将内容扩展到其他视图控制器。

更新

正如评论中所解释的,创建单例类来控制位置管理器和委托方法的好处。通过使用单例,您可以防止多次调用委托方法的可能性。您可以通过仔细编码来防止这种情况发生,但是使用单例可以为您做到这一点。这也是一个很好的类,可以处理委托方法需要完成的所有工作。

  • 感谢您的链接。我很确定我已经涵盖了所有这些基础。在这一点上,我认为更多的是应用程序如何进入和退出后台,而不是区域监控。事实上,它只在 CLLocationManagerDelegate 中工作对我来说很有意义 - didEnterRegion 应该如何被调用?iOS 是否知道足够的信息来唤醒应用程序并实例化正确的 VC?我想知道它是否必须与 UIApplicationDelegate 协议有关。 (2认同)