45

組み込みの Xcode ユニット テスト フレームワークである SenTestingKit を使用して、一部のグランド セントラル ディスパッチ コードのユニット テストに問題がありました。私はこれに自分の問題を解決することができました。ブロックを構築し、メインスレッドで実行しようとする単体テストがあります。ただし、ブロックが実際に実行されることはなく、同期ディスパッチであるためテストがハングします。

- (void)testSample {

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

    STFail(@"FAIL!");
}

これがハングアップする原因となるテスト環境は何ですか?

4

5 に答える 5

113

dispatch_sync指定されたキューでブロックを実行し、完了するのを待ちます。この場合、キューはメインのディスパッチキューです。メインキューは、メインスレッドですべての操作をFIFO(先入れ先出し)の順序で実行します。つまり、を呼び出すたびdispatch_syncに、新しいブロックは行の最後に配置され、キュー内の他のすべてが完了するまで実行されません。

ここでの問題は、メソッド現在メインスレッドで実行されている間、エンキューしたばかりのブロックがメインスレッドでの実行を待機している行の最後にあることです。キューの最後にあるブロックは、現在のメソッド(それ自体)がメインスレッドの使用を終了するまで、メインスレッドにアクセスできません。ただし、ディスパッチキューで実行するためにブロックオブジェクトを送信し、そのブロックが完了するまで待機することを意味します。testSampledispatch_sync

于 2011-10-19T06:03:07.323 に答える
8

コードの問題は、dispatch_syncまたはを使用するかどうかに関係なくdispatch_asyncSTFail()常に呼び出され、テストが失敗することです。

さらに重要なことは、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!");
}
于 2011-10-19T03:24:55.247 に答える
6

メイン キューにいて、メイン キューが使用可能になるのを同期的に待機している場合、実際に長時間待機します。まだメインスレッドにいないことを確認するためにテストする必要があります。

于 2011-10-19T03:33:57.673 に答える
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!");
}
于 2015-04-24T15:01:23.450 に答える