"Failure to deallocate CLLocationManager on the same runloop as its creation may result in a crash"

"Failure to deallocate CLLocationManager on the same runloop as its creation may result in a crash"

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

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 必须在 运行 循环中创建。如果您不这样做,您将收到来自 CoreLocation 的以下警告:

A location manager was created on a dispatch queue executing on a thread other than the main thread. It is the developer's responsibility to ensure that there is a run loop running on the thread on which the location manager object is allocated. In particular, creating location managers in arbitrary dispatch queues (not attached to the main queue) is not supported and will result in callbacks not being received.

在你的例子中,你的 locationManager 看起来像是在 main thread 中创建的,但是 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)
    }

}

告诉我你的想法。