iOS定位问题:didUpdateLocations与授权回调未触发
定位回调未触发问题的解决方案
问题说明
尝试获取设备定位时,locationManager(_:didChangeAuthorization:) 和 locationManager(_:didUpdateLocations:) 两个回调始终无法触发。系统会正常请求定位权限,且已完成授权,但第二次调用startLocation方法时,仅能看到权限授予的打印日志,回调仍无响应。
调用代码如下:
DispatchQueue.global(qos: .background).async { let gpsController = GPSController() gpsController.startLocation() sleep(10) DispatchQueue.main.async { gpsController.startLocation() } }
我的GPSController实现代码:
import Foundation import CoreLocation class GPSController : NSObject, CLLocationManagerDelegate{ let locationManager: CLLocationManager = CLLocationManager() static var lastLocation : CLLocation? = nil func startLocation(){ locationManager.delegate = self // 检查定位服务状态 if CLLocationManager.locationServicesEnabled() { switch locationManager.authorizationStatus { case .notDetermined: print("notDetermined") locationManager.requestWhenInUseAuthorization() break case .restricted, .denied: print("Denied") break case .authorizedWhenInUse, .authorizedAlways: locationManager.startUpdatingLocation() print("authorizedWhenInUse") case .authorized: print("authorized") break @unknown default: print("@unknown") break } } else { print("turn off") } } func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { print("didChangeAuthorization") if manager.authorizationStatus == .authorizedWhenInUse { locationManager.startUpdatingLocation() } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { print("didChangeAuthorization") // 此处打印内容错误,应为didUpdateLocations for currentLocation in locations{ Loge("Location : \(currentLocation)") GPSController.lastLocation = currentLocation } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("error") }
解决方案
1. 核心问题:GPSController实例被提前回收
在后台队列闭包中创建的gpsController是局部变量,当闭包执行周期结束后,该实例会被ARC自动回收,导致CLLocationManager的代理失效,无法触发回调。
修复方式:
- 方式一:通过全局变量或类属性持有实例,保证其生命周期
// 在闭包外部声明持有变量 var gpsController: GPSController? DispatchQueue.global(qos: .background).async { gpsController = GPSController() gpsController?.startLocation() sleep(10) DispatchQueue.main.async { gpsController?.startLocation() } }
- 方式二:将GPSController设计为单例,确保全局唯一且不会被回收
class GPSController : NSObject, CLLocationManagerDelegate{ static let shared = GPSController() // 单例实例 let locationManager: CLLocationManager = CLLocationManager() static var lastLocation : CLLocation? = nil private override init() { // 私有化构造方法,避免创建多个实例 super.init() locationManager.delegate = self // 初始化时统一设置代理,无需重复调用 } // 剩余方法保持不变 } // 调用方式 DispatchQueue.global(qos: .background).async { GPSController.shared.startLocation() sleep(10) DispatchQueue.main.async { GPSController.shared.startLocation() } }
2. 次要问题修正
- 修正
didUpdateLocations中的打印错误,将print("didChangeAuthorization")改为print("didUpdateLocations"),便于确认回调是否触发。 - 确保
Info.plist中添加了对应权限描述:- 使用
requestWhenInUseAuthorization时,需添加NSLocationWhenInUseUsageDescription键并补充描述文本; - 使用
requestAlwaysAuthorization时(iOS 11+),需添加NSLocationAlwaysAndWhenInUseUsageDescription键。
- 使用
内容的提问来源于stack exchange,提问作者RCH
相关产品推荐
相关产品推荐

