2

I have the following bit of code in a class method

NSDictionary *shopAddresses = [[NSDictionary alloc] initWithContentsOfFile:fileName];
NSMutableArray *shopLocations = [NSMutableArray arrayWithCapacity:shopAddresses.count];

[shopAddresses enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id key, ShopLocation *shopLocation, BOOL *stop) {
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:shopLocation.address completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error) {
            NSLog(@"Geocode failed with error: %@", error);
        }
        else {
            shopLocation.placemark = [placemarks objectAtIndex:0];
        }
        [shopLocations addObject:shopLocation];
    }];
}

After execution of this code, I want to return the shopLocations array as a result for the method. However I need to somehow wait until all geocoder searches have finished if I don't want the array to be empty.

How can I do this?

I have tried different GCD approaches, but haven't been successful so far.

Beav
  • 495
  • 2
  • 5
  • 14

1 Answers1

6

This can be handled by the dispatch_group_... functions:

…
dispatch_group_t group = dispatch_group_create();

[shopAddresses enumerateObjectsUsingBlock:^(id key, NSUInteger idx, BOOL *stop) {

    dispatch_group_enter(group);

    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:shopLocation.address completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error) {
            NSLog(@"Geocode failed with error: %@", error);
        }
        else {
            shopLocation.placemark = [placemarks objectAtIndex:0];
        }
        [shopLocations addObject:shopLocation];

        dispatch_group_leave(group);
    }];
}];

while (dispatch_group_wait(group, DISPATCH_TIME_NOW)) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.f]];
}
dispatch_release(group);

…

I'm using these kind of blocks to accumulate some network requests.

I hope this can help.

Markus Hardt
  • 101
  • 3
  • This was easy. I didn't thought about using the dispatch groups manually. – Tobias Kräntzer Mar 28 '12 at 06:46
  • This is one of the solutions I tried, but without success. The dispatch_group_wait function just waited forever. I think this happens because the dispatch_group_leave function is nested in the completion handler block. – Beav Mar 28 '12 at 21:18
  • It is supposed to _wait_ forever. But I just realized that the `-geocodeAddressString:completionHandler:` method is running the block on the main thread. And my solution may stop the runloop. But there is a solution for that as well and I will edit my answer above. – Markus Hardt Mar 29 '12 at 06:17
  • Is it possible to get `dispatch_group_wait` to only wait for a limited time? I tried using it without the while loop and specified `5.0f` rather than `DISPATCH_TIME_NOW` and it didn't seem to wait at all. – ray Oct 11 '12 at 01:00
  • Did you use `dispatch_time()` to create the wait time? The timeout is specified in nanoseconds, so 5.0f would be like nothing compared to `DISPATCH_NOW`. – Markus Hardt Mar 30 '13 at 06:59