Xcode15.3+Swift5.10下UIKit无法显示用户当前位置求助
问题描述
使用Xcode15.3、Swift5.10开发地图功能,需求是用户授权后显示当前位置并添加大头针。已配置Info.plist、相关函数及IBOutlet,但运行时出现以下问题:
- 控制台警告:
This method can cause UI unresponsiveness if invoked on the main thread. Instead, consider waiting for the-locationManagerDidChangeAuthorization:callback and checkingauthorizationStatusfirst - 控制台报错:
Error Domain=kCLErrorDomain Code=1 "(null)" - 地图仅显示英国区域,未加载用户当前位置及大头针
原代码如下:
import UIKit import MapKit class ViewController: UIViewController, CLLocationManagerDelegate { @IBOutlet weak var myMap: MKMapView! let locationManager = CLLocationManager() override func viewDidLoad() { super.viewDidLoad() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest if (CLLocationManager.locationServicesEnabled()) { locationManager.requestLocation() locationManager.startUpdatingLocation() } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { if let userLocation = locations.first { manager.stopUpdatingLocation() let coordinate = CLLocationCoordinate2D(latitude: locationManager.location?.coordinate.latitude ?? 0.0, longitude: locationManager.location?.coordinate.longitude ?? 0.0) let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) let region = MKCoordinateRegion(center: coordinate, span: span) myMap.setRegion(region, animated: true) let myPin = MKPointAnnotation() myPin.coordinate = coordinate myPin.title = "Hey There" myPin.subtitle = "I am here" myMap.addAnnotation(myPin) } } func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { switch manager.authorizationStatus { case .authorizedAlways: return case .authorizedWhenInUse: return case .notDetermined: locationManager.requestWhenInUseAuthorization() case .restricted: locationManager.requestWhenInUseAuthorization() case .denied: return @unknown default: locationManager.requestWhenInUseAuthorization() } } func locationManager(_ manager: CLLocationManager, didFailWithError error: any Error) { print(error) } }
问题原因分析
- 授权时机错误:
viewDidLoad中直接调用位置更新方法,此时可能未获取用户授权,触发权限不足错误(kCLErrorDomain Code=1)。 - 授权回调逻辑缺失:
locationManagerDidChangeAuthorization中,授权成功后未启动位置更新,导致授权完成后无后续位置获取动作。 - 位置获取逻辑冗余:同时调用
requestLocation和startUpdatingLocation,前者是单次获取,后者是持续更新,二者重复调用无意义。 - 坐标获取方式不当:已通过
didUpdateLocations拿到最新位置,却又使用locationManager.location,可能导致空值或旧坐标。
修复后的代码
import UIKit import MapKit class ViewController: UIViewController, CLLocationManagerDelegate { @IBOutlet weak var myMap: MKMapView! let locationManager = CLLocationManager() override func viewDidLoad() { super.viewDidLoad() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest // 主动检查授权状态,触发回调逻辑 locationManagerDidChangeAuthorization(locationManager) } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let userLocation = locations.first else { return } manager.stopUpdatingLocation() // 使用回调中的最新位置坐标 let coordinate = userLocation.coordinate let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) let region = MKCoordinateRegion(center: coordinate, span: span) // 确保UI操作在主线程执行 DispatchQueue.main.async { self.myMap.setRegion(region, animated: true) let myPin = MKPointAnnotation() myPin.coordinate = coordinate myPin.title = "Hey There" myPin.subtitle = "I am here" self.myMap.addAnnotation(myPin) } } func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { switch manager.authorizationStatus { case .authorizedAlways, .authorizedWhenInUse: // 授权成功后启动位置更新 manager.startUpdatingLocation() case .notDetermined: manager.requestWhenInUseAuthorization() case .restricted, .denied: // 权限不足时提示用户去设置开启 let alert = UIAlertController(title: "位置权限不足", message: "请在设置中开启位置权限以获取当前位置", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "取消", style: .cancel)) alert.addAction(UIAlertAction(title: "去设置", style: .default) { _ in guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return } UIApplication.shared.open(settingsURL) }) present(alert, animated: true) @unknown default: manager.requestWhenInUseAuthorization() } } func locationManager(_ manager: CLLocationManager, didFailWithError error: any Error) { print("位置获取失败:\(error.localizedDescription)") } }
关键修复点说明
- 调整授权触发逻辑:
viewDidLoad中主动调用授权检查方法,避免未授权时启动位置更新。 - 完善授权成功处理:授权通过后立即启动位置更新,确保授权后才开始获取位置。
- 优化坐标使用:直接使用回调中的最新位置,避免依赖
locationManager.location的潜在问题。 - 主线程保障UI操作:将地图区域设置和大头针添加放在主线程执行,避免UI卡顿。
- 权限不足提示:针对受限/拒绝状态添加弹窗引导,提升用户体验。
内容的提问来源于stack exchange,提问作者user23509100
相关产品推荐
相关产品推荐

