Ios 用户授权位置使用时的双序列行为
在我的iOS应用程序中,我请求用户获得设备位置的许可。在我的主ViewController上,我有一个导航栏按钮,点击该按钮时,它会向用户请求使用权限。如果用户点击OK,它将被发送到显示本地数据的视图控制器。如果用户点击“取消”,则不会发生任何事情。我还有一个弹出窗口,显示用户何时以及是否再次点击位置按钮,以重定向到设置,从而在先前取消时授权位置使用 该应用程序按照我在模拟器中的预期工作,但当在设备上使用时,当用户点击OK以允许位置使用时,它会切换到本地视图控制器,但会连续切换2到3次 segue从主视图控制器转到本地视图控制器,并使用iAction从按钮点击请求权限 位置信息在主视图控制器中获得,并传递给本地控制器。本地控制器按预期显示所有内容 我如何防止这种双重或三重切换到同一视图控制器 下面是我的代码:Ios 用户授权位置使用时的双序列行为,ios,swift,segue,cllocationmanager,Ios,Swift,Segue,Cllocationmanager,在我的iOS应用程序中,我请求用户获得设备位置的许可。在我的主ViewController上,我有一个导航栏按钮,点击该按钮时,它会向用户请求使用权限。如果用户点击OK,它将被发送到显示本地数据的视图控制器。如果用户点击“取消”,则不会发生任何事情。我还有一个弹出窗口,显示用户何时以及是否再次点击位置按钮,以重定向到设置,从而在先前取消时授权位置使用 该应用程序按照我在模拟器中的预期工作,但当在设备上使用时,当用户点击OK以允许位置使用时,它会切换到本地视图控制器,但会连续切换2到3次 segu
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toLocal" {
let destination = segue.destination as! LocalViewController
destination.latitude = latitude
destination.longitude = longitude
}
}
//MARK: - Location Manager Methods
@IBAction func LocationNavBarItemWasTapped(sender: AnyObject) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[locations.count - 1]
if location.horizontalAccuracy > 0 {
locationManager.stopUpdatingLocation()
latitude = location.coordinate.latitude
longitude = location.coordinate.longitude
}
let status = CLLocationManager.authorizationStatus()
switch status {
case .restricted, .denied:
showLocationDisabledPopUp()
return
case .notDetermined:
// Request Access
locationManager.requestWhenInUseAuthorization()
case .authorizedAlways:
print("Do Nothing: authorizedAlways")
case .authorizedWhenInUse:
self.performSegue(withIdentifier: "toLocal", sender: nil)
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("LocationManager failed with error \(error)")
}
private func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if (status == CLAuthorizationStatus.denied) {
showLocationDisabledPopUp()
}
}
这里的问题是,您正在中执行一个segue
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
可以多次触发(每次从CLLocationManager
发送新位置时)。有几种方法可以解决这个问题,但为了让您尽可能少地改变,我建议:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[locations.count - 1]
if location.horizontalAccuracy > 0 {
locationManager.stopUpdatingLocation()
latitude = location.coordinate.latitude
longitude = location.coordinate.longitude
}
let status = CLLocationManager.authorizationStatus()
switch status {
case .restricted, .denied:
showLocationDisabledPopUp()
return
case .notDetermined:
// Request Access
locationManager.requestWhenInUseAuthorization()
case .authorizedAlways:
print("Do Nothing: authorizedAlways")
case .authorizedWhenInUse:
//-- MODIFIED HERE --
locationManager.stopUpdatingLocation()
locationManager = nil
Dispatch.main.async {
self.performSegue(withIdentifier: "toLocal", sender: nil)
}
}
}
如果有帮助,请告诉我,否则我们可以对您的代码进行更多更改,以解决这个简单的问题
编辑:让你知道:最好在
private func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus)
当状态为
kCLAuthorizationStatusAuthorized
或KClauthorizationStatusAuthorizedWays
或kCLAuthorizationStatusAuthorized时,将根据您的需要继续使用。正如superpuccio所述,主要问题是调用了didUpdateLocations
委托函数多次。我也不知道您为什么要在didUpdateLocations
功能中检查authorizationStatus
,因为在这一点上已经很清楚,用户允许位置访问。我认为函数应该是这样的:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// check for a location that suits your needs
guard let location = locations.last, location.horizontalAccuracy > 0 else { return }
// prevent the manager from updating the location and sending more location events
manager.delegate = nil
manager.stopUpdatingLocation()
// update the local variables
latitude = location.coordinate.latitude
longitude = location.coordinate.longitude
// perform the segue
performSegue(withIdentifier: "toLocal", sender: nil)
}
由于还有一些问题,比如在知道实际授权状态之前启动位置更新,我将提供一个完整的解决方案。如果有任何不清楚的地方,请随时询问:
class ViewController: UIViewController {
var latitude: CLLocationDegrees?
var longitude: CLLocationDegrees?
lazy var locationManager: CLLocationManager = {
let locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
return locationManager
}()
@IBAction func getLocation(_ sender: UIBarButtonItem) {
locationManager.delegate = self
checkAuthorizationStatus()
}
private func checkAuthorizationStatus(_ status: CLAuthorizationStatus? = nil) {
switch status ?? CLLocationManager.authorizationStatus() {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .authorizedWhenInUse:
locationManager.startUpdatingLocation()
default:
showLocationDisabledPopUp()
}
}
func showLocationDisabledPopUp() {
// your popup code
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// your segue code
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkAuthorizationStatus(status)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last, location.horizontalAccuracy > 0 else { return }
manager.delegate = nil
manager.stopUpdatingLocation()
latitude = location.coordinate.latitude
longitude = location.coordinate.longitude
performSegue(withIdentifier: "toLocal", sender: nil)
}
}
我不认为didchangearthorizationstatus
是执行segue的更好的地方,因为在这一点上可能还没有位置。你是对的,但在这一点上,Jose可以确定用户已经接受了位置权限请求。所以他可以去第二个控制器,在那里开始“开火”。不需要开始更新主控制器上的位置,逻辑可以分为两部分:在主控制器中,只需请求权限,在第二种情况下,启动激发位置并向用户显示。但是如果我正确理解了他,主视图控制器现在负责获取位置并将其传递给细节。在这种情况下,您是对的。我知道Jose正在使用从CLLocationManager检索到的第一个位置来说:“好的,一个位置来了,所以所有系统都已启动并运行,我可以继续”。