Search code examples
iosswiftcllocationmanagercllocation

.notDetermined to wait for a response from user


I'm currently experimenting with CLLocation and i recently came across authorizationStatus. I want to show one view if the user allows the app to use location services, and another one if he/she don't. It works as I want it to, except .notDetermined. If I insert it in my .denied-block and press "Allow when in use", I can't render the "allow" page but rather have to restart the app to render it. It's also the other way around if I put it in my .accesWhenInUse-block and press "deny". So my question is, what is a good practice to do with this command? Ideally I want the app to wait until the user actually does a choice and load it from there, but since .notDetermined is required to handle i'm a bit lost.

My init location func so far:

   private func initLocation() {
    self.locationManager.requestWhenInUseAuthorization()
    if CLLocationManager.locationServicesEnabled() {
        switch CLLocationManager.authorizationStatus() {

        case .authorizedWhenInUse, .authorizedAlways  :
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
            locationManager.startUpdatingLocation()
            break

        case .notDetermined:
            break

        case .restricted, .denied:
            print("well this is awkward..")
            view.addSubview(noLocationTextView)

            NSLayoutConstraint.activate([
                noLocationTextView.heightAnchor.constraint(equalToConstant: 210),
                noLocationTextView.widthAnchor.constraint(equalToConstant: 210),
                noLocationTextView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
                noLocationTextView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
                ])

            noLocationTextView.text = "Well we're going to need your location"
            break
        }
      }

    }

I've extracted .notDetermined to its own case right now. So the question is, how do I handle this so that the app waits and loads the proper view when a choice is made?


Solution

  • Thanks to @Paulw11 I managed to fix this by using the delegate method. So instead of using my initLocation() I used this:

     func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    
            switch status {
            case .authorizedWhenInUse, .authorizedAlways:
    
                goToLocationSettings.removeFromSuperview()
                noLocationContainer.removeFromSuperview()
                break
            case .denied, .restricted:
                print("well this is awkward..")
                view.addSubview(noLocationContainer)
    
               NSLayoutConstraint.activate([
                    noLocationContainer.heightAnchor.constraint(equalTo: self.view.heightAnchor),
                    noLocationContainer.widthAnchor.constraint(equalTo: self.view.widthAnchor),
                    ])
    
                noLocationContainer.insertSubview(goToLocationSettings, at: 3)
    
                NSLayoutConstraint.activate([
                    goToLocationSettings.widthAnchor.constraint(equalToConstant: 300),
                    goToLocationSettings.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
                    goToLocationSettings.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 200),
                    goToLocationSettings.heightAnchor.constraint(equalToConstant: 50)
                    ])
    
                break
    
            default:
    
                break
            } 
    }
    

    This way .notDetermined is default which does nothing until the user made a choice, as I wanted. It also changes in real-time so if I deny access to location and then grants it when the app is running it just updates the view and shows the content. Hope this helps someone with a similar problem!