首页 文章

主队列上的dispatch_sync在单元测试中挂起

提问于
浏览
39

我在使用内置的Xcode单元测试框架SenTestingKit测试一些宏的中央调度代码时遇到了一些麻烦 . 我成功地解决了我的问题 . 我有一个单元测试,它构建一个块并尝试在主线程上执行它 . 但是,该块永远不会被实际执行,因此测试会挂起,因为它是同步调度 .

- (void)testSample {

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

    STFail(@"FAIL!");
}

什么是导致它挂起的测试环境?

5 回答

  • 2

    dispatch_sync 在给定队列上运行一个块并等待它完成 . 在这种情况下,队列是主调度队列 . 主队列以FIFO(先进先出)顺序在主线程上运行其所有操作 . 这意味着无论何时调用 dispatch_sync ,您的新块都将放在该行的末尾,并且在队列中的其他所有内容完成之前不会运行 .

    这里的问题是你刚入列的块是在等待在主线程上运行的行的末尾 - 而 testSample 方法 is 当前在主线程上运行 . 在当前方法(本身)完成使用主线程之前,队列末尾的块无法访问主线程 . 但是 dispatch_sync 表示提交块对象以便在调度队列上执行,并等待该块完成 .

  • 8

    您的代码中的问题是,无论您使用 dispatch_sync 还是 dispatch_async ,都将始终调用 STFail() ,从而导致测试失败 .

    更重要的是,正如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!");
    }
    
  • 104

    如果您在主队列中并同步等待主队列可用,您确实会等待很长时间 . 您应该测试以确保您不在主线程上 .

  • 2

    跟进,从那以后

    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!");
    }
    
  • 6

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

    基本上如果:

    • 你是 on FooQueue . (不一定是 main_queue

    • 您使用 sync 调用方法,即以串行方式调用,并希望 execute on FooQueue .

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

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

相关问题