【问题标题】:Efficiency of Google Geocoding with Dispatch Queue - How to Improve - iPhone使用 Dispatch Queue 的 Google 地理编码效率 - 如何提高 - iPhone
【发布时间】:2011-11-29 12:26:14
【问题描述】:

我的应用中有一个谷歌地图视图,该视图通过地理编码填充了引脚。我正在使用下面的代码创建一个调度队列,然后向 Google 查询我的应用中每个地方的经度和纬度。

问题在于,尽管下面的代码在一定程度上有效,但它似乎在第一次运行时遗漏了很大比例的项目。根据下面的代码,这些项目被添加到数组“failedLoad”中。

目前,我正在运行第二种方法来在 failedLoad 中添加位置,每当调用 ViewDidLoad 方法时都会调用该方法。然而,这是一个糟糕的解决方案,因为即使在第二种方法运行之后,failedLoad 中仍然有项目,而且我更希望在不依赖 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];

       });

    });
}   

【问题讨论】:

    标签: iphone objective-c multithreading google-maps geocoding


    【解决方案1】:

    GCD 很棒,但如果 SDK 已经为此提供了异步 API,那么您应该永远不要使用线程技术。在您的情况下,永远不要使用 stringWithContentsOfURL:,因为它是一个同步和阻塞代码(这可能是您切换到使用 GCD 使其在后台运行的原因),而 NSURLConnection 具有异步 API。 当您需要执行任何网络请求时,请始终使用此异步 API

    这更好,原因有很多:

    • 其中一个原因是它已经在 SDK 中为此设计了一个 API(即使您可能需要创建像 MyGeocoder 这样的类来发送请求、处理响应、解析它并以异步方式返回值方式)
    • 但更喜欢异步 API(而不是使用同步 stringWithContentsOfURL + GCD)的最重要原因是 NSURLConnectionNSRunLoop 集成并安排在 runloop 上检索套接字数据,避免为此创建大量无用的线程(如果在非严格需要的地方使用线程,则线程是邪恶的)。
    • 最后,由于 NSURLConnection 生命周期由 RunLoop 自己处理,委托方法已在主线程上调用。

    GCD 总是比直接使用NSThreads 更好,但是对于已经在 SDK 中实现的东西使用 Runloop 调度,尤其是NSURLConnections 总是更好的性能(避免线程调度问题),多线程问题等等更多。


    [编辑] 比如不想自己实现类,可以使用我的示例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);
    }];
    

    【讨论】:

    • 这是一个写得很好的答案,尽管我会说我认为在某些情况下在辅助线程上使用同步网络调用是合适的。
    • 谢谢,但这并不能回答我的问题或解决我的问题。这段代码在运行的时候还是会跳过很多地方。
    • 我猜它跳过了很多地方正是因为你在 GCD 代码中同时运行了很多线程。创建太多线程(使用 GCD 调度的块太多)可能会解释这个问题,因为所有这些线程要调度,如果没有一些请求超时,所有请求都无法同时处理。至少尝试使用NSURLConnection(或OHURLLoader)方法,因为即使我不能保证它会完全解决您的问题,它很可能仍然会减少请求错误(通过使用 RunLoop 调度而不是线程)所以值得使用它。
    猜你喜欢
    • 2011-11-29
    • 1970-01-01
    • 1970-01-01
    • 2017-04-21
    • 2013-06-14
    • 1970-01-01
    • 2019-04-27
    • 1970-01-01
    • 2015-12-23
    相关资源
    最近更新 更多