Since iOS 16/Xcode 14, I get this error:
This method can cause UI unresponsiveness if invoked on the main thread. Instead, consider waiting for the -locationManagerDidChangeAuthorization: callback and checking authorizationStatus first."?
I am observing scrolling freezes and long press freezes.
How should what Apple is suggesting be done?
This is my current code segment
/In ViewDidLoad
if CLLocationManager.locationServicesEnabled() {
let authorizationStatus: CLAuthorizationStatus
if #available(iOS 14, *) {
authorizationStatus = locationManager.authorizationStatus
} else {
authorizationStatus = CLLocationManager.authorizationStatus()
}
switch authorizationStatus {
case .authorizedAlways, .authorizedWhenInUse:
locationManager.delegate = self
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.startUpdatingLocation()
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.allowsBackgroundLocationUpdates = true
//////here data loading happens too////////////
case .notDetermined:
case .restricted:
case .denied:
@unknown default:
print("Location services are not enabled")
}
/outside ViewDidLoad
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
///location database related stuff
}
I tried async/await as suggested here, but it didn't fix the issue. https://developer.apple.com/forums/thread/714467
CodePudding user response:
LocationManager's authorizationStatus
is designed be used when CLLocationManager
delegate indicates that there has been a change in your apps authorisation to use location services.
The system calls the CLLocationManager
delegate method locationManagerDidChangeAuthorization(_ :)
when the app’s authorisation status changes. This could be for user-initiated changes or when the user changes permissions after you request requestWhenInUseAuthorization()
or requestAlwaysAuthorization()
. It will also call the delegate method whenever you create a new CLLocationManager
instance, so it will prompt you to check the value when first run.
When the delegate method is called you should get the value from the authorizationStatus
property and store it. If the status is then changed (manually or in response to system usage prompts) it will be called again and you should update your stored value; if not the value you have saved remains valid and there is no need to request it from your viewDidLoad
.
EDIT to address comment...
You shouldn't be running the location code in viewDidLoad
- this should be initiated from the delegate when you get an updated location. In viewDidLoad initiate the locations services, eg. by calling this :
//struct/class-level properties
var locationManager: CLLocationManager
var authStatus = CLAuthorizationStatus.notDetermined
func startLocationServices() {
locationManager = CLLocationManager()
locationManager.delegate = self
if authStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
locationManager.startUpdatingLocation()
}
Then action location information with the CLLocationManagerDelegate
extension HomeVC: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
authStatus = manager.authorizationStatus
// you could use a `didSet` on `authStatus` to react to changes
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let newLocation = locations.first {
process(newLocation)
}
}
}
and then in the process(_:)
do what you were trying to do in viewDidLoad