3

次のコードがあります。

- (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");
}

以下を生成します。

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...

私の質問は互いに関連しています:

  1. 私の理解が正しければ、メイン キュー (dispatch_get_main_queue()) はシリアル キューです。メイン キュー/メイン スレッドを dispatch_semaphore_wait でブロックしているのに、最初のテスト ケースで「currentRunLoop が実行されているため、ここに到達します」と表示されるのはなぜですか(2 番目のケースは問題ありません。私の理解では、そうです。何をすべきか)?

  2. 現在実行中のタスクがブロックされているシリアルキューで、現在のタスクがロック解除される前に、次のタスク (ああ、この不思議な runLoop:beforeDate:) をディスパッチするにはどうすればよいでしょうか?

非常に多くのことが(SOについても)この問題に依存しているため、これについて詳細かつ包括的な回答を聞きたいです。

更新:受け入れられた回答に加えて、この SO トピックには、この質問に対する適切な回答があります:完了時にメイン キューを呼び出す単体テスト async キューのパターン

4

1 に答える 1

6

メイン スレッドのデフォルトの runloop には、実行時にメイン ディスパッチ キューも処理する特別な動作があるためです。この場合、実際にはブロックしていません。これはdispatch_semaphore_wait、すぐにタイムアウトするように指示しているためです (0 以外を返し、iftrue に評価されます)。現在の実行ループを駆動する while ループを実行します。 、したがって、エンキューされたブロックが実行されます。

しかし、あなたがどの部分に驚いているのかわからないので、私の答えは大雑把です。

于 2012-11-29T07:00:13.920 に答える