I'm using the Kiwi testing framework to test an authentication method in my app. The test freezes at a call to dispatch_sync which looks like this:
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_sync(main, ^
{
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
});
I'd like to know why it freezes there, if anyone has any hints.
For the second part of your question regarding the hint on the freeze:
When calling dispatch_sync
on a queue, always verify that this queue is not already the current queue (dispatch_get_current_queue()
). Because dispatch_sync
will queue your block on the queue passed as the first parameter, and then will wait for this block to be executed before continuing.
So if the dispatch_get_current_queue()
and the queue on which you enqueue your block are the same, namely the main queue in your case, the main queue will block on the call to dispatch_sync until… the main queue as executed the block, but it can't, as the queue is blocked, and you have a beautiful deadlock here.
One solution ([EDIT] up until iOS6):
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_block_t block = ^
{
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
};
if (dispatch_get_current_queue() == main)
block(); // execute the block directly, as main is already the current active queue
else
dispatch_sync(main, block); // ask the main queue, which is not the current queue, to execute the block, and wait for it to be executed before continuing
[EDIT] Be careful, dispatch_get_current_queue()
is only to be used for debugging purposes and never in production. In fact, dispatch_get_current_queue
is deprecated since iOS6.1.3.
If you are in the specific case of the main queue (which is associated with the main thread only), you may instead test [NSThread isMainThread]
as suggested by @meaning-matters.
By the way, are you sure you need to dispatch_sync
in your case?
I guess sending your notification a bit later, avoiding to block until it has been sent, is acceptable in your case, so you may also consider using dispatch_async
(instead of using dispatch_sync
and needing the queue comparison condition), which would avoid the deadlock issue too.
dispatch_get_current_queue()
is deprecated starting from iOS 6, and dispatch_get_current_queue() == dispatch_get_main_queue()
was found to be false
while on main thread on iOS 6.1.3.
In iOS 6 and beyond simply do:
dispatch_block_t block = ^
{
<your code here>
};
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With