【问题标题】:iOS Waiting for Location Manager to InitiOS 等待位置管理器初始化
【发布时间】:2012-12-08 12:49:31
【问题描述】:

我正在开发一个基于地图和位置跟踪的 iOS 应用。当用户第一次启动应用程序时,它会要求允许跟踪位置等。唯一的问题是,当它这样做时,我有代码设置初始地图视图和其他基于位置的变量之前用户点击确定。

我发现我可以将这些启动步骤放在等待用户更改位置管理器权限的 while 循环之后,如下所示,但这可能不是最佳实践,更不用说它会导致一些奇怪的行为启动画面和地图之间的过渡:

BOOL firstrun = TRUE;
while ([[locationManager class] authorizationStatus] == kCLAuthorizationStatusDenied || [[locationManager class] authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
    NSLog(@"Waiting for location permission");
}
...initiation code...

我不知道的位置管理器委托中是否有警报框的“位置访问权限”侦听器或类似功能?我在文档中看不到这种方法。有人知道这里的最佳做法是什么吗?非常感谢。

编辑 我按如下方式开始我的位置跟踪:

if (nil == locationManager)
    locationManager = [[CLLocationManager alloc] init];

[locationManager startMonitoringSignificantLocationChanges];

self.musicmap.delegate = self;
[self.mymap setShowsUserLocation:true];

谢谢

【问题讨论】:

  • 请显示您的位置管理器初始化代码。你是怎么开始的?
  • 我已更新以显示我的初始状态。它基于 Apple 文档中的“重大位置更改”教程。

标签: ios map location cllocationmanager


【解决方案1】:

我建议将您的类设为 CLLocationManagerDelegate,然后实现此方法:

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    //Your code goes here
}

更多关于 CLLocationManagerDelegate 的信息可以在here找到。

希望有帮助!

【讨论】:

  • 我最终这样做了。我在看班级而不是代表!哦!
【解决方案2】:

在用户有时间接受或拒绝位置许可对话之前,我的应用程序和应用程序执行操作遇到了类似的问题。这就是我最终要做的。

-(BOOL)locationAuthorizationStatus {
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
        // user has not authorized us to use location
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Location Denied", @"Location Denied")
                                                        message:NSLocalizedString(@"This app does not have permission to access your location. Please enable location access in device settings.", @"Message stating this app does not have permission to access your location and to enable location permission in settings")
                                                       delegate:self
                                              cancelButtonTitle:NSLocalizedString(@"Ok", @"Ok")
                                              otherButtonTitles: nil];
        [alert show];
        return NO;
    }

    // Check if region monitoring is available for this device
    if (![CLLocationManager regionMonitoringAvailable]) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Geofencing Unavailable", @"Geofencing Unavailable")
                                                        message:NSLocalizedString(@"This device is not able to monitor regions", @"Message stating this device is not able to monitor regions")
                                                       delegate:nil
                                              cancelButtonTitle:nil
                                              otherButtonTitles:NSLocalizedString(@"Ok", @"Ok"), nil];
        [alert show];
        return NO;
    } else {
        if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
            // trigger a location check to prompt user for authorization
            LocationManagerController *locationController = [LocationManagerController sharedManager];
            [locationController.locationManager startUpdatingLocation];
            // the dialogue box is triggered here
            [locationController.locationManager stopUpdatingLocation];
            _waitingOnAuthorization = YES;
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkForAuthorizationStatusChange) name:@"WaitingOnAuthorizationStatus" object:nil];
            return NO;
        }
    }

    return YES;
}

-(void)checkForAuthorizationStatusChange {
    if (_waitingOnAuthorization) {
        // this should only catch location change on first time
        if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized) {
            // user approved location services

        } else {
            // user declined authorization

        }
        // set flag back to NO
        _waitingOnAuthorization = NO;
    }

    // remove our notification observer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

您必须添加适用于您的用例的变量。但这里是它的要点。

  1. 通过 BOOL 方法检查授权状态 (locationAuthorizationStatus)
  2. 如果可以使用位置,返回 YES 做任何你想做的事情
  3. 如果不是,则返回 NO 并提醒用户
  4. 如果是第一次,将启动位置管理器以触发位置对话,然后停止它以节省电池,设置标志并设置通知,以便您知道用户何时点击是或否。
  5. 通知触发方法 checkAuthorizationChangeStatus 并重新检查权限以查看用户所做的事情。从那里,您可以根据用户的选择调用您需要的任何方法。

Apple 没有任何委托方法来捕获此选择,因此解决它的唯一方法有点 hacky。这种方法对我来说效果很好。有点hacky,但有效。希望这会有所帮助。

【讨论】:

    【解决方案3】:
    //Start up motion manager, not sure if you need this for location manager
        motionManager = [[CMMotionManager alloc] init];
        if (motionManager.accelerometerAvailable) {
            motionManager.accelerometerUpdateInterval = 1.0/2.0;
            [motionManager startAccelerometerUpdates];
        }
    
        locationManager = [[CLLocationManager alloc] init];
    
        //We will be the location manager delegate
        locationManager.delegate = self;
    
        //Track position at the 100m accuracy
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    
        //We want to see all location updates, regardless of distance change
        locationManager.distanceFilter = 0.0;
    
        [locationManager startUpdatingLocation];
    

    将上述内容放在“viewDidLoad”或appDelegate“didFinishLaunchingWithOption”中的某个位置

    以下处理更新和内容。 bestLocation 是一个 CLLocation。您需要实现 CLLocationManagerDelegate。 TWO_MINUTES = 120

    - (BOOL)isBetterLocation:(CLLocation *)location {
        if (bestLocation == nil){
            //best location not set yet, so it's a better location by default
            return YES;
        }
    
        // Figure out how long it's been since we got a better location
        NSTimeInterval timeDelta = [location.timestamp timeIntervalSinceDate:bestLocation.timestamp];
    
        BOOL isSignificantlyNewer = timeDelta > TWO_MINUTES;
    
        BOOL isSignificantlyOlder = timeDelta < -TWO_MINUTES;
    
        BOOL isNewer = timeDelta > 0;
    
        if (isSignificantlyNewer) {
            return YES;
        }else if (isSignificantlyOlder) {
            return NO;
        }
    
        CLLocationAccuracy accuracyDelta = location.horizontalAccuracy - bestLocation.horizontalAccuracy;
        //You want accuracy to be low
        BOOL isLessAccurate = accuracyDelta > 0;
        BOOL isMoreAccurate = accuracyDelta < 0;
        BOOL isDifferent = location.coordinate.latitude != bestLocation.coordinate.latitude || 
        location.coordinate.longitude != bestLocation.coordinate.longitude;
    
        if (isMoreAccurate) {
            return YES;
        } else if (isNewer && !isLessAccurate && isDifferent) {
            return YES;
        }
    
        return NO;
    }
    
    
    
    
    
    
    #pragma mark - Location manager delegate
    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
        if ([self isBetterLocation:newLocation]){
            self.bestLocation = newLocation;
    
        } else {
            [locationManager stopUpdatingLocation];
            isLocating = NO;
            NSLog(@"AppDelegate: Turning off location manager >>>>>>>>>>>>>>>>>>>>>");
        }
    }
    

    注意:您不需要“isBetterLocation”方法。这只会检查位置并在大约 2 分钟后关闭位置管理器,这样您就不会耗尽用户的电池。有时您不希望经理离开,所以如果您愿意,可以将其排除在外。

    我不知道你已经做了多少。我就是这样做的。

    【讨论】:

    • 是的,我已经在做所有这些了。正如我所说,跟踪工作正常。我的问题是在全新安装之后,当用户第一次启动应用程序时,我需要一种方法来知道一旦允许位置权限,我就可以更新我的地图位置和其他因变量。
    • 虽然我还没有实现 didUpdateToLocation。也许我可以使用它。我正在看经理而不是代表。我认为 locationManager:didChangeAuthorizationStatus 会做我。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    • 1970-01-01
    • 2016-07-27
    • 2019-03-27
    • 1970-01-01
    • 2020-06-29
    相关资源
    最近更新 更多