CLLocationManager grep местоположение слишком много раз и не точно - PullRequest
0 голосов
/ 20 января 2020

Я пытаюсь создать приложение для watchOS, которое должно отображать позицию, когда пройдено указанное расстояние. Я полностью осознаю, что такое поведение может быть достигнуто благодаря свойству distanceFilter CLLocationManager. Во всяком случае, несмотря на это, мое приложение занимает все больше места, время от времени делая приложение «sh». Я не перемещал свое устройство в течение этого периода времени.

Я хочу отметить, что мой distanceFilter составляет примерно 15 метров, но приложение по-прежнему определяет положение в большинстве случаев.

Для Ради ясности я кратко расскажу о функциональности: имея определенную область, я должен время от времени искать свое местоположение и проверять, содержит ли область его. Если я покину регион, я отправлю уведомление. Вот соответствующий код:


//Premise: Forget Class is a class which contains a region I should monitor.

enum ScanningMode {
    case Precise
    case Normal
    //new
    case Inactive
}

class LocationManager : NSObject, CLLocationManagerDelegate, UNUserNotificationCenterDelegate, ObservableObject {

    let LocMng = CLLocationManager()
    let NotMng = UNUserNotificationCenter.current()
    var modeOfScanning: ScanningMode!
    var forgets = [Forget]()
    private var actualLocation: CLLocation!
    private var actualForget: Forget!
    private var previousForget: Forget!

    override init() {
        super.init()
        modeOfScanning = ScanningMode.Precise

        //temporary
        let latitude = SomeLatitude
        let longitude = SomeLongitude //for privacy reasons
        let radius : Double = 10.0
        let name = "owo"
        let test = [Forget(latitude: latitude, longitude: longitude, radius: radius, name: name, items: ["item"])]
        do {
            let priorArchiver = try JSONEncoder().encode(test)
            UserDefaults.standard.set(priorArchiver, forKey: "frgts")
        } catch {
            print("Can't archive: \(error)")
        }

        if let archive = UserDefaults.standard.object(forKey: "frgts") as? Data {
            let decoder = JSONDecoder()
            if let frgts = try? decoder.decode([Forget].self, from: archive) {
                forgets = frgts
            }
        }

        actualForget = nil
        previousForget = nil
        actualLocation = nil
        resume()

    }

    private func startLocalization(){
        switch modeOfScanning!{
        case ScanningMode.Precise:
            LocMng.desiredAccuracy = kCLLocationAccuracyBest
            LocMng.distanceFilter = 15.0
        case ScanningMode.Normal:
            LocMng.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
            LocMng.distanceFilter = 80.0
        case ScanningMode.Inactive:
            LocMng.desiredAccuracy = kCLLocationAccuracyThreeKilometers
            LocMng.distanceFilter = 9999.0
        }
        LocMng.startUpdatingLocation()
    }

    private func setupManager(){
        LocMng.delegate = self
        LocMng.requestAlwaysAuthorization()
    }

    func resume(){
        setupManager()
        //setupNotification()
        startLocalization()
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == CLAuthorizationStatus.authorizedAlways{
        }
    }

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

        // 1. Block further updates instantly
        updateScanningMode(.Inactive)

        //2. Allow Background Updates
        LocMng.allowsBackgroundLocationUpdates = true

        //3. Grep last location
        let length = locations.count
        actualLocation = locations[length-1]

        //4. Verify if region contains location
        actualForget = checkIfContains()

        //5. Given Previous and Actual Location, compare them
        //Case a: actualLocation is nil and previousLocation is nil

        if actualForget == nil && previousForget == nil{
            // I was out of any location and I'm still out of any location
            updateScanningMode(.Normal)
            print("No updates on location. Out of every region.")
        }

        //Case b: actualForget is nil and previousLocation is not nil
        else if actualForget == nil {
            // I am out of any location but was in a location
            updateScanningMode(.Normal)
            print("I just exited region: \(previousForget.name!).")
            scheduleNotification(forget: previousForget!)
        }

        //Case c: actualForget is not nil and previousLocation is nil
        else if actualForget != nil && previousForget == nil{
            // I was out of a location and I'm now in a location
            updateScanningMode(.Precise)
            print("I just entered region: \(actualForget.name!).")
        }

        //Case d: both not nil (happens rarely)
        else if actualForget != nil && previousForget != nil && actualForget == previousForget{
            updateScanningMode(.Precise)
            print("I just abruptly entered region: \(actualForget.name!).")
            scheduleNotification(forget: previousForget!)
        }

        //Case f: both not nil but equal
        else{
            print("I am still in the region: \(actualForget.name!).")
        }

        //6. Update previousForget
        previousForget = actualForget
    }

    private func checkIfContains() -> Forget? {
        //get all forgets and check if contained in region
        print(actualLocation!)
        for f in forgets{
            let region = f.region
            print(region)
            print(f.name!)
            if region.contains(actualLocation!.coordinate) {
                return f
            }
        }
        return nil
    }

    private func updateScanningMode(_ scan: ScanningMode){
        if scan == .Precise && modeOfScanning != .Precise {
            modeOfScanning = .Precise
            LocMng.desiredAccuracy = kCLLocationAccuracyBest
            LocMng.distanceFilter = 15.0
        }
        else if scan == .Normal && modeOfScanning != .Normal {
            modeOfScanning = .Normal
            LocMng.desiredAccuracy = kCLLocationAccuracyHundredMeters
            LocMng.distanceFilter = 80.0
        }
        else if scan == .Inactive && modeOfScanning != .Inactive {
            modeOfScanning = .Normal
            LocMng.desiredAccuracy = kCLLocationAccuracyThreeKilometers
            LocMng.distanceFilter = 9999.0
        }
    }
}

Результаты консоли:

<+someloc,+someloc> +/- 65.00m (speed -1.00 mps / course -1.00) @ 19/01/2020, 23:22:22 Central European Standard Time
CLCircularRegion (identifier:'owo', center:<+someloc,+someloc>, radius:10.00m)
owo
No updates on location. Out of every region.
<+someloc,+someloc> +/- 65.00m (speed -1.00 mps / course -1.00) @ 19/01/2020, 23:22:31 Central European Standard Time
CLCircularRegion (identifier:'owo', center:<+someloc,+someloc>, radius:10.00m)
owo
No updates on location. Out of every region.
<+someloc,+someloc> +/- 165.00m (speed -1.00 mps / course -1.00) @ 19/01/2020, 23:24:19 Central European Standard Time
CLCircularRegion (identifier:'owo', center:<+someloc,+someloc>, radius:10.00m)
owo
I just entered region: owo.

//I got other 10+ location in less than 1 minute and half WITHOUT MOVING MY WATCH

Заранее спасибо.

...