Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 用户授权位置使用时的双序列行为_Ios_Swift_Segue_Cllocationmanager - Fatal编程技术网

Ios 用户授权位置使用时的双序列行为

Ios 用户授权位置使用时的双序列行为,ios,swift,segue,cllocationmanager,Ios,Swift,Segue,Cllocationmanager,在我的iOS应用程序中,我请求用户获得设备位置的许可。在我的主ViewController上,我有一个导航栏按钮,点击该按钮时,它会向用户请求使用权限。如果用户点击OK,它将被发送到显示本地数据的视图控制器。如果用户点击“取消”,则不会发生任何事情。我还有一个弹出窗口,显示用户何时以及是否再次点击位置按钮,以重定向到设置,从而在先前取消时授权位置使用 该应用程序按照我在模拟器中的预期工作,但当在设备上使用时,当用户点击OK以允许位置使用时,它会切换到本地视图控制器,但会连续切换2到3次 segu

在我的iOS应用程序中,我请求用户获得设备位置的许可。在我的主ViewController上,我有一个导航栏按钮,点击该按钮时,它会向用户请求使用权限。如果用户点击OK,它将被发送到显示本地数据的视图控制器。如果用户点击“取消”,则不会发生任何事情。我还有一个弹出窗口,显示用户何时以及是否再次点击位置按钮,以重定向到设置,从而在先前取消时授权位置使用

该应用程序按照我在模拟器中的预期工作,但当在设备上使用时,当用户点击OK以允许位置使用时,它会切换到本地视图控制器,但会连续切换2到3次

segue从主视图控制器转到本地视图控制器,并使用iAction从按钮点击请求权限

位置信息在主视图控制器中获得,并传递给本地控制器。本地控制器按预期显示所有内容

我如何防止这种双重或三重切换到同一视图控制器

下面是我的代码:

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检索到的第一个位置来说:“好的,一个位置来了,所以所有系统都已启动并运行,我可以继续”。