【问题标题】:How should CLLocationManager status be checked in locationManagerDidChangeAuthorization before loading an iOS view?在加载 iOS 视图之前,应如何在 locationManagerDidChangeAuthorization 中检查 CLLocationManager 状态?
【发布时间】:2022-10-23 21:12:30
【问题描述】:

从 iOS 16/Xcode 14 开始,我收到此错误:

如果在主线程上调用此方法,可能会导致 UI 无响应。相反,请考虑等待 -locationManagerDidChangeAuthorization: 回调并首先检​​查授权状态。”?

我正在观察滚动冻结和长按冻结。

苹果建议的应该怎么做?

这是我当前的代码段

     /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
     }

我按照这里的建议尝试了 async/await ,但它没有解决问题。 https://developer.apple.com/forums/thread/714467

【问题讨论】:

    标签: ios swift objective-c cllocationmanager cllocation


    【解决方案1】:

    LocationManager 的authorizationStatus 设计用于当CLLocationManager 代表表明您的应用程序使用位置服务的授权发生变化时使用。

    当应用的授权状态发生变化时,系统会调用CLLocationManager委托方法locationManagerDidChangeAuthorization(_ :)。这可能是针对用户发起的更改,或者当您请求requestWhenInUseAuthorization()requestAlwaysAuthorization() 后用户更改权限时。每当您创建新的CLLocationManager 实例时,它也会调用委托方法,因此它会在首次运行时提示您检查值。

    当调用委托方法时,您应该从authorizationStatus 属性中获取值并存储它。如果状态随后发生变化(手动或响应系统使用提示),它将再次被调用,您应该更新您的存储值;如果不是,您保存的值仍然有效,无需向您的viewDidLoad 请求。

    编辑以解决评论...

    您不应该在 viewDidLoad 中运行位置代码 - 当您获得更新的位置时,应该从委托发起。在 viewDidLoad 中启动位置服务,例如。通过调用这个:

    //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()
       }
    

    然后用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)
          }
       }
    }
    

    然后在process(_:) 中做你在viewDidLoad 中尝试做的事情

    【讨论】:

    • 那么你会在哪里做呢?在应用程序委托中?问题是,如果状态实际上是 requestWhenInUseAuthorization()requestAlwaysAuthorization(),我只希望 viewDidLoad 代码运行
    • @florida27 查看更新的答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 2018-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多