I\'m just playing around with GCD and I\'ve written a toy CoinFlipper app.
Here\'s the method that flips the coins:
- (void)flipCoins:(NSUInteger)nFl
This is a semi-common question when programming with GCD.
The short answer is that GCD does not have a cancelation API for queues. The rationale:
Given all of these cases, it is far more efficient and powerful to write code like this:
dispatch_async(my_obj->queue, ^{
bool done = false;
// do_full_update() takes too long, therefore:
while ( !my_obj->cancelled && !done ) {
done = do_partial_update(my_obj);
}
});
Oh, and to know if a queue has finished running all of the enqueued blocks, your code can simply execute an empty block with the synchronous API:
dispatch_sync(my_obj->queue, ^{});
As mentioned in the comments, a better way of knowing when your work is done is to use dispatch groups. Dispatch all your blocks to the group and then you can add a completion handler to the group. Once the work is complete, the completion block will run.
dispatch_group_t myGroup = dispatch_group_create();
dispatch_group_async(myGroup, my_obj->queue, ^{
bool done = false;
while ( !my_obj->cancelled && !done ) {
done = do_partial_update(my_obj);
}
});
dispatch_group_notify(myGroup, my_obj->queue, ^{
NSLog(@"Work is done!");
dispatch_release(myGroup);
});
Once all of your blocks have completed, the group will be empty and trigger the notification block. From there, you can update UI, etc.
Good luck and have fun!
How to tell if is running
BOOL dispatch_queue_is_empty(dispatch_queue_t queue)
{
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(queue, ^{
dispatch_group_leave(group);
});
int64_t maxWaitTime = 0.00000005 * NSEC_PER_SEC;
BOOL isReady = dispatch_group_wait(group, maxWaitTime) == 0;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
});
return isReady;
}
To test in app
dispatch_queue_t queue = dispatch_queue_create("test", 0);
NSLog(@"Is empty %@", dispatch_queue_is_empty(queue) ? @"YES" : @"NO");
dispatch_async(queue, ^{
for(int i = 0; i < 100; i++)
{
NSLog(@"... %i", i);
}
});
NSLog(@"Is empty %@", dispatch_queue_is_empty(queue) ? @"YES" : @"NO");
Result
Is empty YES
Is empty NO
... 0
... 1
... 2
... 3
... 4
... 5
... 6
... 7
... 8
... 9
The default value for the variable maxWaitTime
can be tweaked to wanted result.
If you have a serial dispatch queue OR a concurrent dispatch queue, here is a code that can do the same thing.
BOOL __block queueIsEmpty = false;
dispatch_barrier_async (_dispatchQueue, ^{
queueIsEmpty = true;
});
while (!queueIsEmpty) {
int i = 0; // NOOP instruction
}
// At this point your queue should be empty.