«Невозможность освободить CLLocationManager на том же цикле выполнения, что и его создание, может привести к сбою» - PullRequest
0 голосов
/ 13 сентября 2018

Я вижу эту ошибку в консоли и не знаю, в чем причина?Я запрашиваю местоположение пользователя один раз.

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

1 Ответ

0 голосов
/ 31 января 2019

CLLocationManager должно быть создано в цикле выполнения. Если вы этого не сделаете, вы получите следующее предупреждение от CoreLocation:

Менеджер местоположения был создан в очереди отправки, выполняющейся в потоке, отличном от основного потока. Разработчик несет ответственность за обеспечение того, чтобы в потоке, в котором размещен объект диспетчера местоположений, выполнялся цикл выполнения. В частности, создание администраторов местоположений в произвольных очередях отправки (не прикрепленных к основной очереди) не поддерживается и приведет к тому, что обратные вызовы не будут получены.

В вашем случае похоже, что ваш 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)
    }

}

Дайте мне знать, что вы об этом думаете.

...