TL;DR Executive summary :

// open the app permission in Settings app
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)

From the previous Core Location tutorial, we need to prompt an authorization window for user to allow location access in order to get the location data :

location permission

Chances are, the user might decline it on the first run. The bad news is that after the user has declined the prompt, the prompt won't show again even if we call requestWhenInUseAuthorization() later on.

The only way a user can grant location access (or camera, microphone, push notification etc) to an app after declining the first prompt is to go to the Settings app and manually allow permission there.

manually go to Settings

This would require user to open Settings app, scroll down the long list to your app and tap multiple times to allow permission, which can cause annoyance to user. To reduce the cognitive load on the user, we can show an alert with button that links to the app permission section directly using URL(string: UIApplication.openSettingsURLString)! .

// called when the authorization status is changed for the core location permission
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    print("location manager authorization status changed")

    if(status == .denied){
        let alert = UIAlertController(title: "Location access required to get your current location", message: "Please allow location access", preferredStyle: .alert)
        let settingsAction = UIAlertAction(title: "Settings", style: .default, handler: {action in

            // open the app permission in Settings app
            UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
        })

        let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)

        alert.addAction(settingsAction)
        alert.addAction(cancelAction)
      
        alert.preferredAction = settingsAction

        self.present(alert, animated: true, completion: nil)
    }
}

This would result the following output :

Settings Jump