我用单例模式实现了一个符合
CLLocationManagerDelegate
的类。调用 requestWhenInUseAuthorization
(即下面代码中的 requestPermission()
)会提示用户接受,如预期的那样。但是,一旦用户点击“允许一次”,并不总是会调用 locationManagerDidChangeAuthorization(_ manager: CLLocationManager)
。
当它被调用时我没有发现任何模式,当它不被调用时,它似乎非常不一致(它永远不会在第一次调用每个新的应用程序下载时被调用。这种情况在真实设备和模拟器上都会发生。
当我实现一个函数
forceInit()
并在我的应用程序中很早就调用它时,一切都运行良好。因此,我认为这是由于单例被延迟初始化引起的,并且如果单例初始化“太晚”,则委托函数不会被调用。
我做错了什么吗?为什么我需要提前初始化单例,当
requestPermission()
调用需要时无论如何都会初始化单例?
class LocationService: NSObject, CLLocationManagerDelegate {
static var shared: LocationService = LocationService()
@Published private(set) var authorizationStatus: CLAuthorizationStatus
private let clLocationManager: CLLocationManager
public override init() {
clLocationManager = CLLocationManager()
authorizationStatus = clLocationManager.authorizationStatus
super.init()
clLocationManager.delegate = self
clLocationManager.desiredAccuracy = kCLLocationAccuracyBest
clLocationManager.startUpdatingLocation()
}
func forceInit() { // why do I need this? I would rather not explicitly initialise...
authorizationStatus = clLocationManager.authorizationStatus
}
func requestPermission() {
self.clLocationManager.requestWhenInUseAuthorization()
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("AAA NEW AUTH: \(manager.authorizationStatus)") // not printed unless forceInit() is called right on app launch
self.authorizationStatus = manager.authorizationStatus
// TODO
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let newLocation: CLLocation = locations.first else { return }
// do sth
}
}
这也发生在我身上。 对我来说,答案与 CLLocationManager 文档中这个模糊的细节有关:
Core Location 从初始化 CLLocationManager 的线程调用运行循环上委托对象的方法。该线程本身必须有一个活动的运行循环,就像应用程序主线程中的运行循环一样。
我在侧线程中运行大部分初始化,以便我可以同时为启动屏幕设置动画。 一旦侧线程消失,位置管理器委托调用也会消失。
所以我的解决方案是确保在主线程中初始化 CLLocationManager。