I have the following code:
- (void)test_with_running_runLoop { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); NSTimeInterval checkEveryInterval = 0.05; NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue()); dispatch_async(dispatch_get_main_queue(), ^{ sleep(1); NSLog(@"I will reach here, because currentRunLoop is run"); dispatch_semaphore_signal(semaphore); }); while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:checkEveryInterval]]; NSLog(@"I will see this, after dispatch_semaphore_signal is called"); } - (void)test_without_running_runLoop { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue()); dispatch_async(dispatch_get_main_queue(), ^{ sleep(1); NSLog(@"I will not reach here, because currentRunLoop is not run"); dispatch_semaphore_signal(semaphore); }); NSLog(@"I will just hang here..."); while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)); NSLog(@"I will see this, after dispatch_semaphore_signal is called"); } producing the following:
Starting CurrentTests/test_with_running_runLoop 2012-11-29 08:14:29.781 Tests[31139:1a603] Is main queue? : 1 2012-11-29 08:14:30.784 Tests[31139:1a603] I will reach here, because currentRunLoop is run 2012-11-29 08:14:30.791 Tests[31139:1a603] I will see this, after dispatch_semaphore_signal is called OK (1.011s) Starting CurrentTests/test_without_running_runLoop 2012-11-29 08:14:30.792 Tests[31139:1a603] Is main queue? : 1 2012-11-29 08:14:30.797 Tests[31139:1a603] I will just hang here... My questions are related to each other:
If I understand it right, main queue (dispatch_get_main_queue()) is a serial queue. I block the main queue/main thread with dispatch_semaphore_wait, so why do I see the "I will reach here, because currentRunLoop is run" in the first test case (I'm OK with the second case - in my understanding, it does, what it should)?
How a serial queue, having current executing task blocked, can have a next task (oh, this mysterious runLoop:beforeDate:) dispatched before the current one is unlocked?
I want to hear detailed and comprehensive answer on this, because very, very much things (here around on SO too) depend on this issue!
UPDATE: Besides the accepted answer, this SO topic has good answer to this question: Pattern for unit testing async queue that calls main queue on completion