主队列上的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_async
, STFail()
都会被调用,导致你的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!"); }
如果你必须等待自己先出门,你会不会离开家? 你猜对了! 没有! :]
基本上如果:
- 你在FooQueue上 。 (不一定是
main_queue
) - 你使用
sync
的方式调用该方法,即以串行方式,并希望在FooQueue上执行 。
永远不会出于同样的原因,你永远不会离开家!
它不会被派遣,因为它必须等待自己下车!