Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for Asynchronous Operations in Objective-C

I'm googling like crazy and still confused about this.

I want to download an array of file urls to disk, and I want to update my view based on the bytes loaded of each file as they download. I already have something that will download a file, and report progress and completion via blocks.

How can I do this for each file in the array?

I'm ok doing them one at a time. I can calculate the total progress easily that way:

float progress = (numCompletedFiles + (currentDownloadedBytes / currentTotalBytes)) / totalFiles)

I mostly understand GCD and NSOperations, but how can you tell an operation or dispatch_async block to wait until a callback is called before being done? It seems possible by overriding NSOperation, but that seems like overkill. Is there another way? Is it possible with just GCD?

like image 695
Sean Clark Hess Avatar asked Nov 28 '22 16:11

Sean Clark Hess


2 Answers

I'm not sure if I understand you correctly, but perhaps you need dispatch semaphores to achieve your goal. In one of my projects I use a dispatch semaphore to wait until another turn by another player is completed. This is partially the code I used.

for (int i = 0; i < _players.count; i++)
{

    // a semaphore is used to prevent execution until the asynchronous task is completed ...

    dispatch_semaphore_t sema = dispatch_semaphore_create(0);


    // player chooses a card - once card is chosen, animate choice by moving card to center of board ...

    [self.currentPlayer playCardWithPlayedCards:_currentTrick.cards trumpSuit:_trumpSuit completionHandler:^ (WSCard *card) {

        BOOL success = [self.currentTrick addCard:card];

        DLog(@"did add card to trick? %@", success ? @"YES" : @"NO");

        NSString *message = [NSString stringWithFormat:@"Card played by %@", _currentPlayer.name];
        [_messageView setMessage:message];

        [self turnCard:card];
        [self moveCardToCenter:card];


        // send a signal that indicates that this asynchronous task is completed ...

        dispatch_semaphore_signal(sema);

        DLog(@"<<< signal dispatched >>>");
    }];


    // execution is halted, until a signal is received from another thread ...

    DLog(@"<<< wait for signal >>>");

    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    dispatch_release(sema);


    DLog(@"<<< signal received >>>");
like image 172
Wolfgang Schreurs Avatar answered Dec 05 '22 01:12

Wolfgang Schreurs


dispatch groups are the GCD facility designed to track completion of a set of independent or separately async'd blocks/tasks.

Either use dispatch_group_async() to submit the blocks in question, or dispatch_group_enter() the group before triggering the asynchronous task and dispatch_group_leave() the group when the task has completed.

You can then either get notified asynchronously via dispatch_group_notify() when all blocks/tasks in the group have completed, or if you must, you can synchronously wait for completion with dispatch_group_wait().

like image 32
das Avatar answered Dec 05 '22 00:12

das