在创建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失败可能会导致崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

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