luis
luis

Reputation: 2305

How to execute multiple async methods concurrently and get a callback when they all have finished?

I coded the following, but I am not sure if it's working the way it's supposed to:

func loadAssets(assets: [String: [String]]) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) {
        let group = dispatch_group_create()
        for (assetType, ids) in assets {
            switch(assetType) {
            case Settings.imageAssetType:
                for id in ids {
                    dispatch_group_enter(group)
                    Assets.fetchImage(id) { _ in
                        dispatch_group_leave(group)
                    }
                }
            case Settings.soundAssetType:
                for id in ids {
                    dispatch_group_enter(group)
                    Assets.fetchSound(id) { _ in
                        dispatch_group_leave(group)
                    }
                }
            case Settings.jsonAssetType:
                for id in ids {
                    dispatch_group_enter(group)
                    Assets.fetchJSON(id) { _ in
                        dispatch_group_leave(group)
                    }
                }
            case default:
                for id in ids {
                    dispatch_group_enter(group)
                    Assets.fetchClip(id) { _ in
                        dispatch_group_leave(group)
                    }
                }
            }
        }
        dispatch_group_notify(group, main, self.assetsDidLoad)
    }
}

Basically, a method that loads all a bunch of assets using a Dictionary with key values containing the asset type in its keys and a list of asset IDs as the values. Then I am iterating through all these asset ids for each type of asset and calling a method to fetch the asset. (I am not sure that the fetch methods are fully running asynchronously, they might have part of their code synchronously too, these methods will load the assets).

Anyway, what I am trying to do is call the method assetsDidLoad() when all of these fetch methods have finished and therefore, all the assets have been loaded, that's why I am trying to use the dispatch group functionality. However, I am pretty new to this dispatch code and I am not sure if what I am doing right now will work for my purposes.

I would appreciate it if someone could point out if this is ok or maybe to the way I should be approaching this. I would even appreciate a response in Objective-C.

Thanks!

Upvotes: 0

Views: 253

Answers (1)

Mean Dinosaur
Mean Dinosaur

Reputation: 386

Your code looks correct (assuming all your fetch methods are guaranteed to execute their blocks). If assets were to be empty, your notify block would fire immediately. dispatch_group_enter and dispatch_group_leave just need to be balanced and can be called in queue.

For reference, here is some code I used to test some different cases (in Objective-C):

dispatch_queue_t queue = dispatch_queue_create("com.Test.TestQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^
{
    sleep(3);
    printf("\nFirst done!");
});

dispatch_group_async(group, queue, ^
{
    sleep(1);
    printf("\nSecond done!");

    dispatch_group_enter(group);
    sleep(5);
    printf("\nNested done!");
    dispatch_group_leave(group);

});

dispatch_group_async(group, queue, ^
{
    sleep(2);
    printf("\nThird done!");
});

dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
    sleep(10);
    printf("\nAsync done!");
    dispatch_group_leave(group);
});

dispatch_group_notify(group, dispatch_get_main_queue(), ^
{
    printf("\nAll done!");

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Message" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:nil];
    [alertView show];
});

Which ends showing the alert, with this in the debugger:

Second done!
Third done!
First done!
Nested done!
Async done!
All done!

Upvotes: 3

Related Questions