locationManager didUpdateLocations срабатывает дважды на устройстве, только один раз на симуляторе

тот же код, я предполагаю, что устройство фактически обновляет местоположение дважды по какой-то причине, хотя я только вызываю startUpdatingLocation() один раз, и я запускаю некоторые stopUpdatingLocations() внутри didUpdateLocations

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    manager.stopUpdatingLocation()
    let loc: CLLocation = locations[locations.count - 1]
    let id = 0
    let type = 0
    let number = 0

    createNewDataPoint(id, loc: loc, type: type, number: number)
}

в этом случае createNewDataPoint вызывается дважды, создавая 2 новые точки данных. Это происходит только один раз в симуляторе, поэтому я предполагаю, что это имеет какое-то отношение к фактическому устройству и GPS, так как симулятор подделывает его местоположение.

startUpdatingLocation () только в моем коде один раз, на кнопке. В принципе, вы нажимаете кнопку, go go manager.startUpdatingLocations (), didupdatelocations попадает один раз на симулятор, два раза на устройство (идентичные координаты), и он создает 2 новые точки данных.

единственный другой код, который упоминает что-либо связанное, - это установка точности, фильтра, запросов авторизации и ранее упомянутого startUpdatingLocation(). Есть ли что-то, что я могу сделать? убедитесь, что я не создаю вдвое больше точек данных, чем необходимо?

8 ответов


методы делегата диспетчера местоположений могут вызываться очень часто и в любое время.

вы можете, однако, применить следующий алгоритм, чтобы защитить себя:

  1. создать глобальный bool сказать didFindLocation.
  2. Set didFindLocation to false когда вы называете startUpdatingLocation.
  3. внутри делегата перезвоните didUpdateLocations:, если didFindLocation был false, set didFindLocation to true и затем вызов stopUpdatingLocation.

надеюсь, что это помогает.


лучший способ-сделать следующее:

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    manager.stopUpdatingLocation()
    manager.delegate = nil
}

лучшее решение для iOS 10.0+

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    [locationManager stopUpdatingLocation]; // stop location manager
    locationManager.delegate = nil;
    //Your logics... 
    //This will be called only one time now.
}

но не забудьте снова установить делегата.


вы не получите часто на тренажере. и на устройстве, когда вы будете двигаться далеко, тогда только вы получите didUpdateLocations. просто двигайтесь в открытом пространстве, чтобы GPS мог определить ваше местоположение устройства, чтобы получить максимальную точность.


вместо запуска / завершения обновления местоположения и установки делегата на ноль существует метод requestLocation который идеально подходит, когда ваше приложение нужно быстро исправить местоположение пользователя:

документы:

override func viewDidLoad() {
    // Create a location manager object
    self.locationManager = CLLocationManager()

    // Set the delegate
    self.locationManager.delegate = self
}

func getQuickLocationUpdate() {
    // Request location authorization
    self.locationManager.requestWhenInUseAuthorization()

    // Request a location update
    self.locationManager.requestLocation()
    // Note: requestLocation may timeout and produce an error if authorization has not yet been granted by the user
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    // Process the received location update
}

используйте этот метод, если требуется текущее местоположение пользователя, но не нужно оставлять службы location services запущенными.


решение@Zumry Mohamed является правильным

Я пробую код следующим образом:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {

   [self.locationManager stopUpdatingLocation];
   self.locationManager.delegate = nil;
   self.locationManager = nil; 
}

наконец этот делегат вызывается только один раз, теперь я понимаю, почему возникла проблема, просто потому, что менеджер вызывает stopUpdatingLocationметод, но система не помогает нам сделать делегат недействительным, поэтому мы можем получать обратный вызов каждый раз при обновлении местоположения из-за вашего desiredAccuracy и distanceFilter настройки свойства CLLocationManager, поэтому окончательное решение так же, как сказал @Zumry Mohamed, мы можем вручную установить делегат в ноль, когда мы stopUpdateLocation. надеюсь, это поможет вам понять, что происходит, почему это может решить проблему.


locationManager.startUpdatingLocation () непрерывно извлекает местоположение и несколько раз вызывает метод didUpdateLocations, Просто установите значение для locationManager.значение distanceFilter перед вызовом locationManager.startUpdatingLocation().

по мере того как я установил 200 метров(вы можете изменить как ваше требование) работая отлично

    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.distanceFilter = 200
    locationManager.requestWhenInUseAuthorization()
    locationManager.startUpdatingLocation()

после получения желаемой широты и долготы просто позвонить stopUpdatingLocation()и установить делегат nil.

В Swift 3:

locationManager.stopUpdatingLocation() 
locationManager.delegate = nil

В Objective-C:

[locationManager stopUpdatingLocation]
locationManager.delegate = nil

здесь locationManager объект CLLocationManager.