iOS GCD Sync with Async Block

I have an async function with a block :

[self performAsyncTaskCompletion:(void(^) () )
 {
   //Do Something
 }
];

I need to call this function many times but in a synchronous way. I tried to use GCD queues :

  • Objective-C Asynchronous Web Request with Cookies
  • Completion handlers and return values
  • How to make ui responsive all the time and do background updating?
  • IOS How do I asynchronously download and cache images and videos for use in my app
  • What's the difference between synchronous and asynchronous calls in Objective-C, versus multi-threading?
  • TestCase : SwiftHTTP library not making the HTTP call
  • dispatch_queue_t queue = dispatch_queue_create("com.MyApp.task", NULL);
    for (int i = 0; i < array.count; i++)
    {
       dispatch_sync(queue, ^{
         [self performAsyncTaskCompletion:(void(^) () )
          {
            //Do Something
          }
          ];
       });
    }
    

    But it doesn’t work because dispatch_sync is only waiting for the end of the block.
    How can I ask it to wait for the end of the async functions in its block ?

    2 Solutions Collect From Internet About “iOS GCD Sync with Async Block”

    You could use dispatch group if you want to initiate some process upon the completion of a series of asynchronous tasks, but would like to allow those tasks to run concurrently with respect to each other (which, especially with network requests, can offer much better performance than running them sequentially):

    dispatch_group_t group = dispatch_group_create();
    
    for (int i = 0; i < array.count; i++) {
        dispatch_group_enter(group);
        [self performAsyncTaskCompletion: ^{
            //Do Something
            dispatch_group_leave(group);
        }];
    }
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // do this when its all done
    });
    

    Personally, I’d might even be inclined to perform a more radical refactoring of performAsyncTaskCompletion, using an asynchronous NSOperation subclass pattern instead. Then you could add these to a NSOperationQueue with maxConcurrentOperationCount specified, thereby achieving the same concurrency while also controlling the degree of concurrency. But hopefully the above illustrates the idea: Run tasks concurrently, but detect the completion of those tasks without ever blocking the main thread.

    You can use dispatch_async with semaphores:

    Example:

    - (void)performAsyncTaskCompletion:(void (^)())block {
        if (block) {
            block();
        }
    }
    
    - (void)runChainOfOperations {
        static dispatch_once_t onceToken;
        static dispatch_semaphore_t semaphore;
        static dispatch_queue_t queue;
        dispatch_once(&onceToken, ^{
            semaphore = dispatch_semaphore_create(1);
            queue = dispatch_queue_create("com.MyApp.task", NULL);
        });
    
        NSArray *array = @[@1, @2, @3, @4, @5];
        static long counter = 0;
        for (int i = 0; i < array.count; i++) {
            dispatch_async(queue, ^{
                dispatch_semaphore_wait(semaphore,  DISPATCH_TIME_FOREVER);
                [self performAsyncTaskCompletion:^{
                    sleep(10);
                    dispatch_async(dispatch_get_main_queue(), ^{
                         NSLog(@"%ld", counter++);
                    });
                    dispatch_semaphore_signal(semaphore);
                 }];
            });
        }
    

    }

    Console output:

    2015-04-12 21:28:06.047 HKTest[9497:1136830] 0
    2015-04-12 21:28:16.023 HKTest[9497:1136830] 1
    2015-04-12 21:28:26.025 HKTest[9497:1136830] 2
    2015-04-12 21:28:36.029 HKTest[9497:1136830] 3
    2015-04-12 21:28:46.031 HKTest[9497:1136830] 4