Поведение двойного перехода, когда пользователь разрешает использование местоположения - PullRequest
0 голосов
/ 19 декабря 2018

В моем приложении для iOS я запрашиваю у пользователя разрешение на определение местоположения устройства.На моем главном ViewController у меня есть кнопка панели навигации, при нажатии которой у пользователя запрашивается разрешение на использование.Если пользователь нажмет OK, он будет отправлен на контроллер представления, который отображает локальные данные.Если пользователь нажимает Отмена, то ничего не происходит.У меня также есть всплывающее окно, когда и если пользователь снова нажимает на кнопку местоположения, чтобы перенаправить на настройки, чтобы разрешить использование местоположения, если оно было ранее отменено.

Приложение работает так, как я планировал в симуляторе, но при использованиина устройстве, когда пользователь нажимает кнопку «ОК», чтобы разрешить использование местоположения, он переходит к локальному контроллеру представления, но делает это 2 или 3 раза подряд.

Переход переходит от контроллера основного представления к контроллеру локального просмотра.и он запрашивает разрешения от нажатия кнопки, используя IBAction.

Информация о местоположении получается в контроллере основного вида и передается в локальный контроллер.Локальный контроллер отображает все как положено.

Как я могу предотвратить этот двойной или тройной переход к одному и тому же View Controller?

Ниже мой код:

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()
    }
}

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Как уже заявлено superpuccio , основная проблема заключается в том, что функция делегата didUpdateLocations вызывается несколько раз.Я также не знаю, почему вы проверяете authorizationStatus в функции didUpdateLocations, поскольку в этот момент уже ясно, что пользователь разрешил доступ к местоположению.По моему мнению, функция должна выглядеть примерно так:

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)
    }

}
0 голосов
/ 19 декабря 2018

Проблема здесь в том, что вы выполняете переход в

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 или kCLAuthorizationStatusAuthorizedAlways или kCLAuthorizationStatusAuthorizedWhenInUseв зависимости от ваших потребностей.

...