主队列上的dispatch_sync在unit testing中挂起

我有一些麻烦的unit testing一些大的中央调度代码与内置的Xcodeunit testing框架SenTestingKit。 我设法解决了我的问题。 我有一个unit testing,build立一个块,并试图在主线程上执行它。 但是,该块从未实际执行,所以testing挂起,因为它是一个同步调度。

- (void)testSample { dispatch_sync(dispatch_get_main_queue(), ^(void) { NSLog(@"on main thread!"); }); STFail(@"FAIL!"); } 

testing环境是什么造成这个挂起?

dispatch_sync在给定的队列上运行一个块并等待它完成。 在这种情况下,队列是主调度队列。 主队列按照先入先出的顺序在主线程上运行所有操作。 这意味着每当你调用dispatch_sync ,你的新块将被放在行的末尾,并且不会运行,直到队列中的所有内容完成为止。

这里的问题是,你刚刚入队的块在主线程上等待运行的那一行结束 ,而testSample方法当前正在主线程上运行。 直到当前方法(本身)完成使用主线程后,队列末尾的块才能访问主线程。

代码中的问题是不pipe你使用dispatch_sync还是dispatch_asyncSTFail()都会被调用,导致你的testing失败。

更重要的是,正如BJ Homer的解释,如果你需要在主队列中同步运行一些东西,你必须确保你不在主队列中,否则会发生死锁。 如果你在主队列中,你可以简单地将该块作为常规函数运行。

希望这可以帮助:

 - (void)testSample { __block BOOL didRunBlock = NO; void (^yourBlock)(void) = ^(void) { NSLog(@"on main queue!"); // Probably you want to do more checks here... didRunBlock = YES; }; // 2012/12/05 Note: dispatch_get_current_queue() function has been // deprecated starting in iOS6 and OSX10.8. Docs clearly state they // should be used only for debugging/testing. Luckily this is our case :) dispatch_queue_t currentQueue = dispatch_get_current_queue(); dispatch_queue_t mainQueue = dispatch_get_main_queue(); if (currentQueue == mainQueue) { blockInTheMainThread(); } else { dispatch_sync(mainQueue, yourBlock); } STAssertEquals(YES, didRunBlock, @"FAIL!"); } 

如果你在主队列上并同步等待主队列可用,那么你确实会等待很长时间。 您应该testing以确保您不在主线程中。

跟进,因为

 dispatch_get_current_queue() 

现在已经被弃用了,你可以使用

 [NSThread isMainThread] 

看看你是否在主线上。

所以,使用上面的其他答案,你可以这样做:

 - (void)testSample { BOOL __block didRunBlock = NO; void (^yourBlock)(void) = ^(void) { NSLog(@"on main queue!"); didRunBlock = YES; }; if ([NSThread isMainThread]) yourBlock(); else dispatch_sync(dispatch_get_main_queue(), yourBlock); STAssertEquals(YES, didRunBlock, @"FAIL!"); } 

如果你必须等待自己先出门,你会不会离开家? 你猜对了! 没有! :]

基本上如果:

  1. 在FooQueue上 。 (不一定是main_queue
  2. 你使用sync的方式调用该方法,即以串行方式,并希望在FooQueue执行

永远不会出于同样的原因,你永远不会离开家!

它不会被派遣,因为它必须等待自己下车!