Why is this dispatch_sync() call freezing?

后端 未结 2 452
萌比男神i
萌比男神i 2020-12-02 14:42

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         


        
相关标签:
2条回答
  • 2020-12-02 15:18

    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);
    }
    
    0 讨论(0)
  • 2020-12-02 15:24

    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.

    0 讨论(0)
提交回复
热议问题