0

My issue is simple. I have 3 tasks, one is triggered by an NSNotification. How to I wait for all task to be completed before proceeding.

So far, I tried using dispatch group but can't find a way to add the task triggered by NSNotification. (I tried adding the dispatch command within the method triggered by the NSNotification, but if the notification comes after task 1 and 2, it's too late to add to the group as it is already completed.)

_asyncDispatch = dispatch_group_create();


dispatch_group_async(_asyncDispatch,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    [self doTask1];
});

dispatch_group_async(_asyncDispatch,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    [self doTask2];
});

dispatch_group_notify(_asyncDispatch,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {

    // We're done!
});
GrandSteph
  • 2,053
  • 1
  • 16
  • 23

2 Answers2

0

I suggest you to use NSOperation and NSOperationQueue instead. You can link all operations as a dependency to each other and wait until all three will be done. Then in the last operation's completion block do your done handler.

If you're confused with it, you can still use dispatch group, but in slightly another way. Use dispatch_group_enter/dispatch_group_leave + dispatch_group_wait. Something like that:

dispatch_group_t waitGroup = dispatch_group_create();
dispatch_group_enter(waitGroup);
dispatch_async(otherQueue, ^{
    //long-running code
    dispatch_group_leave(waitGroup);
}
dispatch_group_wait(waitGroup, DISPATCH_TIME_FOREVER);

call dispatch_group_enter when one of your task begins running and dispatch_group_leave after task has been completed. Call dispatch_group_wait in the place where you need to wait until all tasks will be completed. Do not wait in the main thread! It is better to create a separate queue for this.

But i encourage you to use NSOperations. It's pretty much more controllable and able to cancel.

Sega-Zero
  • 3,034
  • 2
  • 22
  • 46
  • Tried that, but I still hit the same roadblock. How do I add the method that is triggered by the NSNotification ? – GrandSteph Jun 15 '15 at 18:23
  • I'm not quite understand what your problem is? You want tasks 1 and 2 wait for NSNotification is triggered? Or you want to wait for 3 tasks, one of those is created with NSNotification at any point of time and then call some code? – Sega-Zero Jun 15 '15 at 18:34
  • second option sir! :) I want to wait for 3 tasks, one of those is created with NSNotification at any point of time and then call some code – GrandSteph Jun 15 '15 at 19:51
  • 1
    Well, i see here one appropriate and one bad solution:) **1.** (good) Create `NSOperation` for 1st and 2nd task. Create `NSOperation` that waits for `NSNotification`. Create another `NSOperation` with dependency to all 3 previous `NSOperation`s that will do the completion code. 3rd `NSOperation` should wait for semaphore with `dispatch_semaphore_wait`. When `NSNotification` occurs - signal this semaphore with `dispatch_semaphore_signal`. **2.** (bad) increment some atomic variable in your class each time the task ends. In setter check for value 3 and run completion code. – Sega-Zero Jun 15 '15 at 20:25
  • I guess my ignorance boils down to that : "Create NSOperation that waits for NSNotification" Can you share some code snippet doing just that. I can figure out the rest. In the mean time, I'll do bad option :) – GrandSteph Jun 15 '15 at 20:38
  • Made [this](https://gist.github.com/Sega-Zero/ac0b1dc5fa093939938c) gist for better understanding on a good solution – Sega-Zero Jun 15 '15 at 20:58
  • Thanks. I"m going to try that and will get back to you so you can post answer if it works for proper credit. Thanks for the help. – GrandSteph Jun 15 '15 at 21:02
0

Thanks @Sega-Zero for your guidance. Here is the solution I implemented.

_operationQueue = [[NSOperationQueue alloc] init];
_semaphore = dispatch_semaphore_create(0);

NSOperation *uploadOperation = [NSBlockOperation blockOperationWithBlock:^{
    [self doFirstTask];
}];

NSOperation *downloadOperation = [NSBlockOperation blockOperationWithBlock:^{
    dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
}];
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
    [self doNextMethod];
}];

[completionOperation addDependency:uploadOperation];
[completionOperation addDependency:downloadOperation];

[_operationQueue addOperations:@[uploadOperation, downloadOperation, completionOperation] waitUntilFinished:NO];

And then, in the method triggered by the NSNotification

-(void)methodTriggeredByNotif:(NSNotification *)notification {

// doing some serious stuff here and when done
dispatch_semaphore_signal(_semaphore);}

Voila. Thanks to all.

GrandSteph
  • 2,053
  • 1
  • 16
  • 23