CLLocationManager отзывчивость - PullRequest
12 голосов
/ 17 марта 2012

У меня есть приложение, которое вращается вокруг GPS устройства и информации, получаемой с него.Важно, чтобы данные о местоположении были точными и актуальными.Я знаю, что устройство ограничено его GPS и пределами GPS, но мне было интересно, есть ли что-нибудь, что я могу сделать, чтобы настроить / улучшить производительность iPhone GPS, особенно в области скорости.Поскольку обновления местоположения отстают примерно на 3-5 секунд от местоположения устройства в реальном времени, скорость, сообщаемая менеджером местоположения, также значительно отстает от значения в реальном времени.В моем случае это просто слишком долго.Я понимаю, что я ничего не могу поделать, но кто-нибудь имел успех в улучшении отзывчивости iPhone GPS?Каждый маленький кусочек имеет значение.

Редактировать 1:

Мой диспетчер местоположений находится в одноэлементном классе, как рекомендует Apple.1008 *

Внутри MapView.m (где фактически используется менеджер местоположений):

- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil {
    //setup
    [SingletonDataController sharedSingleton].locationManager.delegate = self;
    //more setup
}

- (void)batteryChanged {
    if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)) {
        [SingletonDataController sharedSingleton].locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    } else {
        [SingletonDataController sharedSingleton].locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    }
}

- (void)viewDidLoad {
    //setup
    [[NSNotificationCenter defaultCenter]
      addObserver:self 
         selector:@selector(batteryChanged) 
             name:UIDeviceBatteryStateDidChangeNotification 
           object:nil];
    //other setup
}

Обработка данных происходит внутри locationManager:didUpdateToLocation:fromLocation:.Я не верю, что неэффективность здесь является причиной задержки.

locationManager:didUpdateToLocation:fromLocation: вызывает этот метод для обновления интерфейса:

- (void)setLabels:(CLLocation*)newLocation fromOldLocation:(CLLocation*)oldLocation {
    //set speed label
    if(iterations > 0) {
        if(currentSpeed > keyStopSpeedFilter) {
            if(isFollowing) {
                [mapViewGlobal setRegion:MKCoordinateRegionMake([newLocation coordinate], mapViewGlobal.region.span)];
            }

            NSString* currentSpeedString;
            if(isCustomary) {
                currentSpeedString = [[NSString alloc] initWithFormat:@"%.1f miles per hour", (currentSpeed * 2.23693629f)];
            } else {
                currentSpeedString = [[NSString alloc] initWithFormat:@"%.1f km per hour", (currentSpeed * 3.6f)];
            }

            [speedLabel setText:currentSpeedString];
            [currentSpeedString release];
        } else {
            speedLabel.text = @"Not moving";
        }
    }

    //set average speed label
    if(iterations > 4 && movementIterations > 2) {
        NSString* averageSpeedString;
        if(isCustomary) {
            averageSpeedString = [[NSString alloc] initWithFormat:@"%.1f miles per hour", (float)((speedAverages / (long double)movementIterations) * 2.23693629f)];
        } else {
            averageSpeedString = [[NSString alloc] initWithFormat:@"%.1f km per hour", (float)((speedAverages / (long double)movementIterations) * 3.6f)];
        }
        [averageSpeedLabel setText:averageSpeedString];
        [averageSpeedString release];
    }

    //set elapsed time label
    NSInteger seconds = [[NSDate date] timeIntervalSinceDate:dataObject.locationManagerStartDate];
    NSInteger minutes = seconds / 60;
    NSInteger hours = minutes / 60;

    //get remainder
    seconds %= 60;

    NSString* timeString;
    NSString* secondsString;
    NSString* minutesString;
    NSString* hoursString;

    if((seconds % 60) < 10) {
        secondsString = [[NSString alloc] initWithFormat:@"0%i", seconds];
    } else {
        secondsString = [[NSString alloc] initWithFormat:@"%i", seconds];
    }

    if((minutes % 60) < 10) {
        minutesString = [[NSString alloc] initWithFormat:@"0%i", minutes];
    } else {
        minutesString = [[NSString alloc] initWithFormat:@"%i", minutes];
    }

    if((hours % 60) < 10) {
        hoursString = [[NSString alloc] initWithFormat:@"0%i", hours];
    } else {
        hoursString = [[NSString alloc] initWithFormat:@"%i", hours];
    }

    timeString = [[NSString alloc] initWithFormat:@"%@:%@:%@", hoursString, minutesString, secondsString];

    [elapsedTimeLabel setText:timeString];

    [timeString release], timeString = nil;
    [secondsString release], secondsString = nil;
    [minutesString release], minutesString = nil;
    [hoursString release], hoursString = nil;

    NSString* totalDistanceString;
    if(isCustomary) {
        totalDistanceString = [[NSString alloc] initWithFormat:@"Total: %.2f mi", (float)distance * 0.000621371192f];
    } else {
        totalDistanceString = [[NSString alloc] initWithFormat:@"Total: %.2f km", (float)distance / 1000.0f];
    }
    [customTopBar setTitle:totalDistanceString];
    [totalDistanceString release];
}

С парой NSDates и NSLogsобнаружил, что выполнение всего locationManager:didUpdateToLocation:fromLocation: (а не только метода обновления метки) никогда не занимает более 8 мс на моем iPhone 4;другими словами, обработка данных не является проблемой.

Ответы [ 3 ]

27 голосов
/ 31 марта 2012

ОК, пара вещей может улучшить ваше отставание. Прежде всего, всегда используйте kCLLocationAccuracyBestForNavigation. Между этим и kCLLocationAccuracyBest нет реальной разницы в использовании батареи, они оба используют GPS на максимальной скорости. Основное отличие заключается в пост-обработке, которую делает Apple.

Во-вторых, нет необходимости фильтровать по скорости == 0. Apple уже выполняет эту фильтрацию: если ваша скорость от GPS падает ниже определенного порога (около 4 км / ч), ОС предполагает, что вы стоите, и он заменяет одно и то же значение местоположения для всех последующих выборок. Он делает это, пока не подумает, что вы снова двигаетесь. Я предполагаю, что они делают это, чтобы избежать "дрожания" на карте, когда вы стоите на месте. Фактически, скорость падает до 0 уже для последнего действительного значения последовательности «стоячих» значений, поэтому, если вы фильтруете по скорости == 0, то вам не хватает одного реального образца GPS.

К сожалению, они не могут избежать этой фильтрации и получить реальные образцы GPS. Я говорил об этом с Apple, и они ответили, что не собираются менять поведение. kCLLocationAccuracyBestForNavigation выполняет менее агрессивную фильтрацию, чем kCLLocationAccuracyBest, поэтому лучше использовать это.

В-третьих, вы, вероятно, уже делаете это, но убедитесь, что вы вызываете "setNeedsDisplay" в своем представлении прямо из "didUpdateFromLocation:", чтобы убедиться, что карта фактически перерисовывается.

Если вы сделаете все это, у вас будет задержка около 1 секунды. Если вы хотите улучшить на 1 секунду, чем вы можете попробовать использовать методы прогнозирования. Из двух последних местоположений и заданной скорости вы можете вычислить, где, вероятно, будет следующее местоположение, и уже отобразить это местоположение. У меня были смешанные результаты с этим. Он хорошо работает для быстрого движения, которое не меняет скорость внезапно, как при вождении автомобиля. Он работает менее хорошо для более медленных движений, таких как ходьба или езда на велосипеде.

6 голосов
/ 31 марта 2012

В iPhone мы можем настроить службы определения местоположения двумя способами -

  1. Используя Standard Location Services, это спутниковый GPS, который предоставляет вам более точные данные.
  2. Используя Significant Location Changes который использует A-GPS или получает местоположение через Wi-Fi, который предоставляет менее точные данные.

Мы можем настроить службы определения местоположения любым из этих двух методов, но это зависит от требований приложения,Если это приложение navigation app или location tracking app, то нам следует использовать Standard Location Services, но перед использованием стандартных служб мы помним, что если вам нужны более точные данные, вам придется страдать с battery consume more quickly.Если приложение не требует обновления местоположения чаще, а также accuracy doesn't matter, то нам следует Significant Location Changes, поскольку оно будет save a lot of battery потреблять по сравнению со стандартной службой определения местоположения.

Стандартная служба определения местоположения использует *Значение 1020 * и distanceFilter для определения того, когда и когда следует доставлять событие.

desiredAccuracy - это параметр, с помощью которого вы можете определить, какую точность вы хотите получить от оборудования GPS.Он использует некоторые заранее заданные константы, так как -

kCLLocationAccuracyBestForNavigation
kCLLocationAccuracyBest
kCLLocationAccuracyNearestTenMeters
kCLLocationAccuracyHundredMeters
kCLLocationAccuracyKilometer
kCLLocationAccuracyThreeKilometers

distanceFilter - это параметр, в котором вы должны определить расстояние, означает, на сколько разрыва расстояния вы хотите попросить оборудование GPS отправить обновление местоположения.

В вашем случае вы имеете дело с параметром скорости, так что я думаю, это связано с навигацией.Поэтому вы должны использовать Standard Location Services.Я думаю, что вы тоже это делаете, но проблема, с которой вы сталкиваетесь, заключается в отставании между обновлениями местоположения.Здесь я предлагаю вам изменить значение desiredAccuracy и distanceFilter на это -

[locationManager setDesiredAccuracy: kCLLocationAccuracyNearestTenMeters];[locationManager setDistanceFilter: 10.0f];

, установив для него значения, вы получите обновление местоположения менее чем за 1 секунду, если вы за рулем.

Еще одна вещь, которую вы должны запомнитьчто при получении обновления местоположения вы должны проверить его значение timestamp, чтобы игнорировать старые обновления местоположения.Это потому, что когда вы набираете locationManager, позвонив по номеру startUpdatingLocation, первое полученное вами местоположение может быть вашим старым местоположением.Также вы должны проверить значение horizontalAccuracy, потому что первые несколько обновлений местоположения, которые вы получаете, всегда не точны и могут иметь точность в 1000 или более, что вы не ищете.Поэтому вы должны проверить его значение, чтобы игнорировать неточные обновления местоположения.

Note: If you try with different accuracy and different distance filter value then you will be more clear about it how accurate data iPhone GPS hardware return.
1 голос
/ 31 мая 2012

Помимо других хороших примеров использования Core Location, также помните об общей методике получения хороших результатов кинематики с не очень хорошим датчиком (например, услугами определения местоположения смартфона) Kalman Filtering .

Это много математики, тестов и настроек, но это позволяет вам получить то, что пользователи посчитают лучшими результатами, чем простые данные от датчика.

Это то, что используется в авионике и таких вещах, как системы обработки радаров.

...