对多个位置进行地理编码-知道何时“全部"完成块已被调用 [英] Geocoding Multiple Locations - Knowing When "All" Completion Blocks Have Been Called

查看:95
本文介绍了对多个位置进行地理编码-知道何时“全部"完成块已被调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用CoreLocation的地理编码器来获取多个地图项的CLLocation坐标.地理编码器会在每个项目完成时调用一个完成块.

I am using the CoreLocation's geocoder to get the CLLocation coordinates for multiple map items. The geocoder calls a completion block on completion for each item.

当所有包含异步地理编码器调用的全部完成后,如何创建类似的块功能? (我可以使用手动计数器.但是必须有一个更优雅的解决方案)

How do I create a similar block functionality which is called when all of these containing asynchronous geocoder calls have been completed? (I could use a manual counter. But there must be a more elegant solution)

到目前为止,这是我的地理编码功能.它将遍历一系列位置项,并为每个位置项启动新的地理编码过程.

Here's my geocoding function so far. It loops through an array of location items and starts a new geocoding process for each.

-(void)geoCodeAllItems {
    for (EventItem* thisEvent in [[EventItemStore sharedStore] allItems]) {
        if (![thisEvent eventLocationCLLocation]){ //Only geocode if the item has no location data yet
            CLGeocoder *geocoder = [[CLGeocoder alloc]init];
            [geocoder geocodeAddressString:[thisEvent eventLocationGeoQuery] completionHandler:^(NSArray *placemarks, NSError *error) {
                if (error){
                     NSLog(@"\t Geo Code - Error - Failed to geocode";
                     return;
                 }
                 if (placemarks)
                 {
                     if ([placemarks count] > 1) NSLog(@"\t Geo Code - Warning - Multiple Placemarks (%i) returned - Picking the first one",[placemarks count]);

                     CLPlacemark* placemark = [[CLPlacemark alloc]initWithPlacemark:[placemarks objectAtIndex:0]];
                     CLLocationCoordinate2D placeCoord = [[placemark location]coordinate];
                     [thisEvent setEventLocationCLLocation:[[CLLocation alloc]initWithLatitude:placeCoord.latitude longitude:placeCoord.longitude]];

                     [[EventItemStore sharedStore] saveItems];
                 } else {
                     NSLog(@"\t Geo Code - Error - No Placemarks decoded");
                 }
             }];
            geocoder = nil;
        } 
    } 
}

这基本上是可行的,但是由于异步方式,我不知道何时所有地理编码活动最终结束.

This basically works however due to the asynchronous fashion I don't know when all geocoding activity has finally ended.

我的感觉是,我要么为此创建一个区块,要么使用Grand Central Dispatch,但我不确定.感谢您在此方面寻求正确方法的帮助.

My feeling is, I either have to create an block for this or use Grand Central Dispatch but I am not really sure. I appreciate any help on this to find the right approach.

推荐答案

您可以使用GCD调度组来执行此操作.另外,我认为您可以用一个CLGeocoder发出多个请求.

You can use a GCD dispatch group to do this. Also, I think you can make multiple requests with a single CLGeocoder.

由于我们可能根本不需要创建组和地址解析器,因此我们将懒惰地创建它们:

Since we might not need to create the group and the geocoder at all, we'll create them lazily:

-(void)geocodeAllItems {
    dispatch_group_t group = NULL;
    CLGeocoder *geocoder = nil;

我们遍历项目,跳过已进行地理编码的项目:

We loop over the items, skipping the ones that have already been geocoded:

    for (EventItem *item in [[EventItemStore sharedStore] allItems]) {
        if (item.eventLocationCLLocation)
            continue;

现在,我们找到了一个需要进行地理编码的代码,如果需要,我们可以创建地址解析器和分配组:

Now that we've found one that needs geocoding, we create the geocoder and the dispatch group if we need to:

        if (!geocoder) {
            geocoder = [[CLGeocoder alloc] init];
            group = dispatch_group_create();
        }

我们将使用帮助程序方法对此项进行地理编码:

We'll use a helper method to geocode just this item:

        [self geocodeItem:item withGeocoder:geocoder dispatchGroup:group];
    }

现在,我们已经遍历所有项目,我们将检查是否对任何项目进行了地理编码:

Now that we've gone through all the items, we'll check whether we geocoded any:

    if (group) {

如果我们对任何一个都进行了地理编码,那么调度组中就会有块.我们将要求该组在其为空时执行一个通知块:

If we geocoded any, then there are blocks in the dispatch group. We'll ask the group to execute a notification block when it becomes empty:

        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"note: all geocoding requests have completed");
        });

最后,我们需要释放组以平衡dispatch_group_create返回的+1保留计数:

Finally, we need to release the group to balance the +1 retain count returned by dispatch_group_create:

        dispatch_release(group);
    }
}

以下是仅对一项进行地理编码的辅助方法:

Here's the helper method that geocodes just one item:

- (void)geocodeItem:(EventItem *)item withGeocoder:(CLGeocoder *)geocoder dispatchGroup:(dispatch_group_t)group {

我们进入"小组.这会自动增加组的成员资格计数器:

We "enter" the group. This increments the group's membership counter atomically:

    dispatch_group_enter(group);

然后我们可以开始地理编码:

Then we can start the geocoding:

    [geocoder geocodeAddressString:item.eventLocationGeoQuery completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error) {
            NSLog(@"error: geocoding failed for item %@: %@", item, error);
        } else {

            if (placemarks.count == 0) {
                NSLog(@"error: geocoding found no placemarks for item %@", item);
            } else {
                if (placemarks.count > 1) {
                    NSLog(@"warning: geocoding found %u placemarks for item %@: using the first", item, placemarks.count);
                }
                CLPlacemark* placemark = placemarks[0];
                thisEvent.eventLocationCLLocation = placemarks[0].location;
                [[EventItemStore sharedStore] saveItems];
            }
        }

在地理编码完成块中,完成所有工作后,我们离开"该组,这会减少其成员计数:

In the geocoding completion block, after all the work is done, we "leave" the group, which decrements its membership count:

        dispatch_group_leave(group);
    }];
}

成员资格计数为零时,组将执行我们在geocodeAllItems末尾添加的通知块.

When the membership count goes to zero, the group will execute the notification block we added at the end of geocodeAllItems.

这篇关于对多个位置进行地理编码-知道何时“全部"完成块已被调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆