当前位置权限对话框消失得太快了。

184
我的应用程序获取用户位置,获取坐标,并提供到目的地或起点的距离。所有这些可能的目的地都显示在表视图中,因此我在填充表格的同时获取用户坐标。唯一的问题是,询问用户位置的警告视图出现后便立即消失,根本无法单击它!有没有办法在应用程序首次加载时手动显示此警告?我尝试在应用程序加载时获取用户位置以尝试强制显示警报,但这并没有起作用。
12个回答

744

虽然很难追踪,但这个问题的解决方案非常简单。

在进行任何位置服务的访问时,如果应用程序尝试首次访问,则会弹出位置访问对话框。经过多次尝试和错误,我发现,如果用户在响应对话框之前释放了 CLLocationManager 对象,则该对话框会自动消失(无需任何用户交互)。

在我的 viewDidLoad 方法中创建了一个 CLLocationManager 实例。由于这是方法级别的局部变量,所以实例在方法执行完成后,由 ARC 释放了。一旦实例被释放,对话框就会消失。解决方案很简单。将 CLLocationManager 实例从方法级变量更改为类级实例变量。现在,只有在卸载类时才会释放 CLLocationManager 实例。


130
我希望我能给你 +100 分。 - coder
1
刚在使用 Xamarin.iOS 时遇到了同样的问题。将 CLLocationManager 类作用域设置为全局后,对话框仍然可见。 - Krumelur
1
如果你能自己加薪,那就太好了。开玩笑的,这对我来说也是个大救赎。 - Garfonzo
2
我也要加入这个派对。在这里,接受我的网络高五! - Matthieu Riegler
3
如果你在Swift中遇到了这个问题,请确保将LocationManager的声明移到viewDidLoad之外。干杯! - KD.
显示剩余11条评论

7
我曾经遇到过类似的情况。经过调试,我发现:
let locationManager = CLLocationManager()

该方法作用域内调用了locationManager,但应该在全局范围内调用。

为什么呢?

简单来说,locationManager在方法返回后被释放了。但它直到用户授权或拒绝之前都不应该被释放。


7
相同的症状,不同的原因:不要连续调用 startUpdatingLocation 由于我错误地构建了代码,导致无意中连续两次调用 startUpdatingLocation ,这显然是不好的。这也可能与队列的选择有关,因为我正在等待网络请求的结果来开始更新,但我不需要进行任何GCD操作来修复它……只需要确保不重复启动即可。
希望有人能够从我的错误中受益。 :)

4
我知道这是一个非常晚的回复,但它可能有助于某些人。 我也遇到了同样的问题,并花了一个小时来确定问题。 起初我的代码是这样的。
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];

CLLocation *location = locationManager.location;
//my stuff with the location

    [locationManager release];

现在位置警报很快就消失了。当我取消注释最后一行时,它可以正常工作。
   // [locationManager release];

3
这是真的。我要补充的唯一注意事项是,当您的项目启用ARC时,您不需要在代码中包含释放语句,但仍会遇到此问题。在这种情况下解决问题的唯一方法是将变量从方法级别提升为类级别。 - Zoli

4

我也遇到了同样的问题(至少症状相似)。

在我的情况下,问题出现在- (void)applicationWillResignActive:(UIApplication *)application;方法中,因为我正在准备进入后台转换而释放我的CLLocationManager实例。当我将其从该方法中移除并仅留在- (void)applicationDidEnterBackground:(UIApplication *)application;中时,问题就解决了。
棘手之处在于,Core Location警报在应用程序仍在前台运行时会挂起你的应用程序。
希望这对你有所帮助,对我来说,寻找这个混蛋花费了很多时间 :)


3
我也遇到了这个问题,但我的解决方案完全不同于被接受的答案。
在我的应用程序中,我从applicationWillResignActive调用stopUpdatingLocation。 这是一个问题,因为当权限对话框出现时会调用applicationWillResignActive。这导致stopUpdatingLocationstartUpdatingLocation之后立即停止工作,这就是为什么对话框会立即消失的原因。
解决方案很简单,只需要改为在applicationDidEnterBackground中调用stopUpdatingLocation即可。

2

Swift 4 和 iOS 11:

请确保在你的.plist文件中已添加隐私权限行(总是使用时),并向你的项目添加CoreLocation框架。

当我更改了以下内容后,位置权限对话框正确显示:

locationManager.requestAlwaysAuthorization()

使用:

locationManager.requestWhenInUseAuthorization()

P.S.: 我已经尝试了所有建议,但都失败了(请求授权到viewDidLoad,使用var代替let来处理locationManager,不要在请求后启动startUpdatingLocation()..我认为这是一个错误,希望他们能尽快解决它..


我也遵循了所有的建议,但我总是遇到同样的问题。位置权限对话框会短暂地出现,然后立即消失。然后我的通知对话框权限出现(这个是正常的),当我按接受或拒绝时,另一个位置权限出现(这次它停留并让我接受或拒绝)。 - user7219266
@BitoQ 是的,对我来说也是一样的情况。虽然我们至少可以看到这个对话框,但我希望在下一个iOS 11.1版本中他们能够修复这个bug。 - Alessandro Ornano

2

我在使用iOS模拟器时遇到了这个问题。后来我发现是因为我的运行方案正在模拟位置,导致了这个弹窗被关闭。我认为这与在启动时调用 locationManager.startUpdatingLocation() 的效果相同。

在编辑方案对话框中取消勾选“允许位置模拟”复选框可以解决此问题。一旦设置好权限并正常工作,您可以重新启用位置模拟,随后模拟器将正常工作。


这对我来说在某种程度上起作用了。至少我能看到对话框。 - CppChase

2

我将locationManager作为实例变量,但在Swift 5、Xcode 11中仍然没有帮助(请参见下文):

class MapViewController: UIViewController {
    
    var locationManager: CLLocationManager {
        let locationManager = CLLocationManager()
        locationManager.desiredAccuracy = .greatestFiniteMagnitude
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        return locationManager
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.startUpdatingLocation()
    }
}

然而,将locationManager变量设置为lazy可以解决该问题:

class MapViewController: UIViewController {

    lazy var locationManager: CLLocationManager = {
        let locationManager = CLLocationManager()
        locationManager.desiredAccuracy = .greatestFiniteMagnitude
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        return locationManager
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.startUpdatingLocation()
    }
}

1

SWIFT 4 @Zoli 的解决方案将如下所示:

class WhateverViewController: UIViewController {
    let locationManager = CLLocationManager() // here is the point of the @Zoli answer

    // some code
    override func viewDidLoad() {
        super.viewDidLoad()

        // some other code
        locationManager.requestWhenInUseAuthorization()
        // some other code
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接