iOS 27:在访问CLLocationManager.authorizationStatus() 时,应用会冻结
- 我遇到了一个奇怪的问题,这个问题只在iOS 27上出现。
- 我有一个基本的
LocationManager实现:
``` import Foundation import CoreLocation import UIKit
class LocationManager: NSObject, CLLocationManagerDelegate {
static let shared = LocationManager()
private let manager = CLLocationManager()
private let geocoder = CLGeocoder()
// MARK: - Public API
func fetchLocationIfNeeded() {
manager.delegate = self
handleAuthorization(CLLocationManager.authorizationStatus())
}
private func handleAuthorization(_ status: CLAuthorizationStatus) {
switch status {
case .notDetermined:
manager.requestWhenInUseAuthorization()
case .restricted, .denied:
showLocationPermissionAlert()
case .authorizedWhenInUse, .authorizedAlways:
manager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
manager.requestLocation()
@unknown default:
break
}
}
private func showLocationPermissionAlert() {
let alertController = UIAlertController(
title: "Location Access Required",
message: "Please enable location access in Settings to use this feature.",
preferredStyle: .alert
)
alertController.addAction(UIAlertAction(title: "Open Settings", style: .default, handler: { _ in
if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(settingsURL)
}
}))
if let topController = UIApplication.shared.windows.first?.rootViewController {
topController.present(alertController, animated: true)
}
}
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) {
handleAuthorization(status)
}
// MARK: - Location
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else { return }
geocoder.reverseGeocodeLocation(location) {
placemarks,
error in
guard error == nil,
let postalCode = placemarks?.first?.postalCode,
!postalCode.isEmpty else { return }
print("zipcode :", postalCode)
globalZipCode = postalCode
NotificationCenter.default.post(
name: NSNotification.Name("ZipcodeGet"),
object: nil
)
}
}
func locationManager(_ manager: CLLocationManager,
didFailWithError error: Error) {
print("Location error: ", error.localizedDescription)
}
}
``
* 在 iOS 27 上,应用在进入handleAuthorization(_:)` 之前似乎会冻结。
* 看起来触发问题的那一行是:
handleAuthorization(CLLocationManager.authorizationStatus())
* 在调试器中检查该值时,第一次得到的输出是:
po CLLocationManager.authorizationStatus()
warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available.
* 再次运行相同的命令会得到:
po CLLocationManager.authorizationStatus()
__C.CLAuthorizationStatus
* 我已经确认需要的权限键存在于 Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>We use your location to determine your ZIP code.</string>
* 相同的实现对较旧的应用可以正常工作,但这个项目在iOS 27上才会出现问题。
* 有没有人遇到过类似的问题,或者知道在iOS 27中对 CLLocationManager.authorizationStatus() 或定位授权处理有任何变化吗?
解决方案
- 经过大量调试,我发现问题似乎与直接操作由
CLAuthorizationStatus枚举返回的值有关:
CLLocationManager.authorizationStatus().rawValue
- 作为一个变通办法,我把
fetchLocationIfNeeded()从:
handleAuthorization(CLLocationManager.authorizationStatus())
- 改为:
let status = CLLocationManager.authorizationStatus().rawValue
switch status {
case CLAuthorizationStatus.notDetermined.rawValue: // notDetermined
manager.requestWhenInUseAuthorization()
case CLAuthorizationStatus.restricted.rawValue,
CLAuthorizationStatus.denied.rawValue: // restricted, denied
showLocationPermissionAlert()
case CLAuthorizationStatus.authorizedAlways.rawValue,
CLAuthorizationStatus.authorizedWhenInUse.rawValue: // authorizedAlways, authorizedWhenInUse
manager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
manager.requestLocation()
default:
break
}
- 这个变通方法在较旧的iOS版本和iOS 27上都能正确工作。
原始值代表的含义
CLLocationManager.authorizationStatus().rawValue返回一个Int32值:
0 = notDetermined
1 = restricted
2 = denied
3 = authorizedAlways
4 = authorizedWhenInUse
- 因此,你也可以使用基于整型的switch:
switch status {
case 0: // notDetermined
manager.requestWhenInUseAuthorization()
case 1, 2: // restricted, denied
break
case 3, 4: // authorizedAlways, authorizedWhenInUse
manager.requestLocation()
default:
break
}
- 我还测试了使用实例属性:
CLLocationManager().authorizationStatus,但那也不起作用。在调试器中对其进行求值时显示为:
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x0).
The process has been returned to the state before expression evaluation.
- 因此,如果你在iOS 27上遇到这个问题,使用
CLLocationManager.authorizationStatus().rawValue并与原始整数值进行比较,似乎是一个可靠的变通办法,同时也与较旧的iOS版本保持兼容。