在创建CLLocationManager的同一运行循环上取消分配CLLocationManager失败可能会导致崩溃

quot;Failure to deallocate CLLocationManager on the same runloop as its creation may result in a crashquot;(在创建CLLocationManager的同一运行循环上取消分配CLLocationManager失败可能会导致崩溃)
本文介绍了在创建CLLocationManager的同一运行循环上取消分配CLLocationManager失败可能会导致崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在控制台中看到此错误,但不确定原因是什么?我正在请求用户位置一次。

2018-09-12 20:04:26.912292-0400 Watch Extension[40984:3250895] [Client] Failure to deallocate CLLocationManager on the same runloop as its creation may result in a crash

代码如下:

import CoreLocation


class WorkoutLocationManager: NSObject, CLLocationManagerDelegate {

    private var locationManager: CLLocationManager?
    public var formattedWorkoutAddress: String?

    public func getWorkoutLocation() {
        guard CLLocationManager.locationServicesEnabled() else {
            print("User does not have location services enabled")
            return
        }

        locationManager = CLLocationManager()
        locationManager?.delegate = self
        locationManager?.desiredAccuracy = kCLLocationAccuracyNearestTenMeters

        let locationAuthorizationStatus = CLLocationManager.authorizationStatus()

        switch locationAuthorizationStatus {
        case .authorizedAlways:
            print("location authorized Always")
            locationManager?.requestLocation()
        case .authorizedWhenInUse:
            print("location authorized When in Use")
            locationManager?.requestLocation()
        case .denied:
            print("location authorization denied")
        case .notDetermined:
            print("location authorization not determined")

        case .restricted:
            print("location authorization restricted")

        }

    }


    // MARK: - CLLocationManagerDelegate

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

                guard let currentLocation = locations.first else { return }

                let geocoder = CLGeocoder()
                geocoder.reverseGeocodeLocation(currentLocation) { (placemarksArray, error) in

                    if let unwrappedError = error  {
                        print("Geocoder error: (unwrappedError)")
                    }

                    guard let placemarksArrayUnwrapped = placemarksArray else  { return }

                    if placemarksArrayUnwrapped.count > 0 {

                        if let placemark = placemarksArray?.first {

                            let name = placemark.name ?? ""
                            let subLocality = placemark.subLocality ?? ""
                            let locality = placemark.locality ?? ""
                            let state = placemark.administrativeArea ?? ""

//                            print("address1:", placemark.thoroughfare ?? "")
//                            print("address2:", placemark.subThoroughfare ?? "")
//                            print("city:",     placemark.locality ?? "")
//                            print("state:",    placemark.administrativeArea ?? "")
//                            print("zip code:", placemark.postalCode ?? "")
//                            print("country:",  placemark.country ?? "")

                            let workoutLocationAsString = (name + " " + subLocality + " " + locality + " " + state)
                            print("workoutLocationAsString = (workoutLocationAsString)")
                            self.formattedWorkoutAddress = workoutLocationAsString

                        } else { print("no placemark")}
                    } else { print("placemark.count = 0")}
                }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("location manager error = (error)")
    }

}

用法:

private func handleWorkoutSessionState(didChangeTo toState: HKWorkoutSessionState,
                                           from fromState: HKWorkoutSessionState) {
        switch (fromState, toState) {
        case (.notStarted, .running):
            workoutLocationManager.getWorkoutLocation() 

推荐答案

CLLocationManager必须在Run循环中创建。如果您不这样做,您将收到来自CoreLocation的以下警告:

在主线程以外的线程上执行的调度队列上创建了位置管理器。开发人员有责任确保在分配位置管理器对象的线程上运行Run循环。特别是,不支持在任意调度队列(未附加到主队列)中创建位置管理器,这将导致无法接收回调。

在您的情况下,它看起来像是在main thread中创建的locationManager,但WorkoutLocationManager的一个实例正在其他某个线程上使用,这会导致在此线程中释放它,从而在同一个线程中释放locationManager

一种选择是确保您的WorkoutLocationManager实例将被创建并仅在主线程中使用。

我还没有完全测试过的另一种选择是尝试强制在主线程中创建和释放locationManager,如下所示:

class WorkoutLocationManager: NSObject {

    var locationManager: CLLocationManager!

    override init() {
        super.init()
        self.performSelector(onMainThread: #selector(initLocationManager), with: nil, waitUntilDone: true)
    }

    @objc private func initLocationManager() {
        self.locationManager = CLLocationManager()
        self.locationManager.delegate = self
    }

    @objc private func deinitLocationManager() {
        locationManager = nil
    }

    deinit {
        self.performSelector(onMainThread: #selector(deinitLocationManager), with: nil, waitUntilDone: true)
    }

}

让我知道你的想法。

这篇关于在创建CLLocationManager的同一运行循环上取消分配CLLocationManager失败可能会导致崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Why local notification is not firing for UNCalendarNotificationTrigger(为什么没有为UNCalendarNotificationTrigger触发本地通知)
iOS VoiceOver functionality changes with Bundle Identifier(IOS画外音功能随捆绑包标识符而变化)
tabbar middle tab out of tabbar corner(选项卡栏中间的选项卡角外)
Pushing UIViewController above UITabBar(将UIView控制器推送到UITabBar上方)
Dropbox Files.download does not start when number of files in folder is gt; 1000(当文件夹中的文件数为1000时,Dropbox Files.Download不会启动)
How can I sync two flatList scroll position in react native(如何在本机Reaction中同步两个平面列表滚动位置)