gran33
gran33

Reputation: 12981

Where is the GCD mechanism invoked?

I follow RAY WENDERLICH GCD tutorial- part 2, and I don't get this:

First implementation

    - (void)downloadPhotosWithCompletionBlock:(BatchPhotoDownloadingCompletionBlock)completionBlock
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // 1
 
        __block NSError *error;
        dispatch_group_t downloadGroup = dispatch_group_create(); // 2
 
        for (NSInteger i = 0; i < 3; i++) {
            NSURL *url;
            switch (i) {
                case 0:
                    url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
                    break;
                case 1:
                    url = [NSURL URLWithString:kSuccessKidURLString];
                    break;
                case 2:
                    url = [NSURL URLWithString:kLotsOfFacesURLString];
                    break;
                default:
                    break;
            }
 
            dispatch_group_enter(downloadGroup); // 3
            Photo *photo = [[Photo alloc] initwithURL:url
                                  withCompletionBlock:^(UIImage *image, NSError *_error) {
                                      if (_error) {
                                          error = _error;
                                      }
                                      dispatch_group_leave(downloadGroup); // 4
                                  }];
 
            [[PhotoManager sharedManager] addPhoto:photo];
        }
        dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER); // 5
        dispatch_async(dispatch_get_main_queue(), ^{ // 6
            if (completionBlock) { // 7
                completionBlock(error);
            }
        });
    });
}

Second Implementation:

    - (void)downloadPhotosWithCompletionBlock:(BatchPhotoDownloadingCompletionBlock)completionBlock
{
    // 1
    __block NSError *error;
    dispatch_group_t downloadGroup = dispatch_group_create(); 
 
    for (NSInteger i = 0; i < 3; i++) {
        NSURL *url;
        switch (i) {
            case 0:
                url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
                break;
            case 1:
                url = [NSURL URLWithString:kSuccessKidURLString];
                break;
            case 2:
                url = [NSURL URLWithString:kLotsOfFacesURLString];
                break;
            default:
                break;
        }
 
        dispatch_group_enter(downloadGroup); // 2
        Photo *photo = [[Photo alloc] initwithURL:url
                              withCompletionBlock:^(UIImage *image, NSError *_error) {
                                  if (_error) {
                                      error = _error;
                                  }
                                  dispatch_group_leave(downloadGroup); // 3
                              }];
 
        [[PhotoManager sharedManager] addPhoto:photo];
    }
 
    dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{ // 4
        if (completionBlock) {
            completionBlock(error);
        }
    });
}

I the first implementation the relevant code is surrounded with dispatch_async and everything is super clear.

BUT, the second implementation is unclear! I don't get it, how the GCD mechanism is taking any part beside of the notification for enter and leave?

Upvotes: 2

Views: 271

Answers (2)

Renato Stauffer
Renato Stauffer

Reputation: 813

The first implementation runs a background thread starting at

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // 1

So the whole function runs there. But this background thread gets eventually blocked at this line (it waits for all the photos to be downloaded):

 dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER);

This is all fine since you are not blocking the main thread. But it is a bit of a clumsy implementation since,

  • you block a thread where you really have not to and
  • the code looks a bit ugly with the dispatch_async around the whole function.

So the second implementation has two benefits:

  • It's not that "ugly" and a bit more readable (because you get rid of the dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{})
  • and there is no block, because dispatch_group_notify serves as the asynchronous completion block.

Upvotes: 2

gnasher729
gnasher729

Reputation: 52592

The first method is an asynchronous method. You can call it from any thread, including the main thread. It will perform actions in a background thread, and when it's done, it will dispatch the callback block on the main thread. A call to this method returns immediately, the callback will be called a lot later.

The second method is a blocking method. The method will not finish until the photos are downloaded, and then it calls your callback method. This method should most definitely not be called from the main thread, only from a background thread.

Upvotes: 0

Related Questions