Эффективность геокодирования Google с очередью рассылки - как улучшить - iPhone - PullRequest
2 голосов
/ 02 октября 2011

В моем приложении есть вид Google Map, который заполняется булавками с помощью геокодирования. Я использую приведенный ниже код для создания очереди отправки, которая затем запрашивает у Google долготу и широту для каждого места в моем приложении.

Проблема в том, что, хотя приведенный ниже код работает в некоторой степени, кажется, что он пропускает большой процент элементов при первом запуске. Эти элементы добавляются в массив failLoad в соответствии с кодом ниже.

В данный момент я запускаю второй метод для добавления мест в failedLoad, который вызывается всякий раз, когда вызывается метод ViewDidLoad. Однако это плохое решение, так как даже после запуска второго метода все еще есть элементы в failLoad, и я также предпочел бы загружать все выводы без использования ViewDidLoad (который вызывается только если пользователь нажимает на вывод, а затем возвращает из представленного подробного экрана).

Кто-нибудь может предложить хороший способ улучшить этот процесс?

Спасибо

-(void)displayPlaces {

for (PlaceObject *info in mapLocations) {

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^

   {

        // GET ANNOTATION INFOS
        NSString * addressOne = info.addressOne;
        NSString * name = info.name;
        NSString * postCode = info.postCode;

        NSString * addressTwo = [addressOne stringByAppendingString:@",London,"];
        NSString * address = [addressTwo stringByAppendingString:postCode];

        NSError * error;

        NSString *urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

        NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString ] encoding:NSASCIIStringEncoding error:&error];
        NSArray *listItems = [locationString componentsSeparatedByString:@","];

        double latitude = 0.0;
        double longitude = 0.0;

        if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:@"200"]) {
            latitude = [[listItems objectAtIndex:2] doubleValue];
            longitude = [[listItems objectAtIndex:3] doubleValue];

        } 

        else {

            NSLog(@"Error %@",name);
            [failedLoad addObject : info];

        }        

        CLLocationCoordinate2D coordinate;
        coordinate.latitude = latitude;
        coordinate.longitude = longitude;
        MyLocation *annotation = [[[MyLocation alloc] initWithName:name address:address coordinate:coordinate] autorelease];

        dispatch_sync(dispatch_get_main_queue(), ^{

            // ADD ANNOTATION
            [mapViewLink addAnnotation:annotation];

       });

    });
}   

1 Ответ

1 голос
/ 02 октября 2011

GCD - это здорово, но вы должны никогда использовать методы потоков, если SDK уже предлагает для этого асинхронный API. В вашем случае никогда не используйте stringWithContentsOfURL:, поскольку это синхронный и блокирующий код (вероятно, поэтому вы переключаетесь на использование GCD, чтобы сделать его в фоновом режиме), в то время как NSURLConnection имеет асинхронный API. всегда используйте этот асинхронный API вместо того, чтобы выполнять любой сетевой запрос .

Это лучше по многим причинам:

  • один из них заключается в том, что это API, уже разработанный для этого в SDK (даже если вам, вероятно, потребуется создать класс, подобный MyGeocoder, который отправляет запрос, обрабатывает ответ, анализирует его и возвращает значение в асинхронном режиме способ)
  • но наиболее значимой причиной для предпочтения асинхронного API (по сравнению с использованием синхронного stringWithContentsOfURL + GCD) является то, что NSURLConnection интегрируется с NSRunLoop и планирует получение данных сокета в runloop , избегая создания множества бесполезных потоков для этого (и потоки являются злыми, если вы используете их там, где это строго не нужно).
  • И, наконец, поскольку жизненный цикл NSURLConnection обрабатывается самим RunLoop, методы делегата уже вызываются в главном потоке.

GCD всегда лучше, чем использование NSThreads напрямую, но использование планирования Runloop для вещей, которые уже созданы в SDK, особенно NSURLConnections всегда лучше как с точки зрения производительности (избегайте проблем с планированием потоков), так и с многопоточностью больше.


[EDIT] Например, если вы не хотите реализовывать класс самостоятельно, вы можете использовать мой пример OHURLLoader класса и использовать его следующим образом:

NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURL* url = [NSURL URLWithString:urlString];
NSURLRequest* req = [NSURLRequest requestWithURL:url];

OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) {
    NSString* locationString = loader.receivedString;
    NSArray *listItems = [locationString componentsSeparatedByString:@","];
    ... etc ...
    // this callback / block is executed on the main thread so no problem to write this here
    [mapViewLink addAnnotation:annotation];
} errorHandler:^(NSError *error) {
    NSLog(@"Error while downloading %@: %@",url,error);
}];
...