21

GCDブロックで繰り返しタイマーを作成すると、なぜ機能しないのか疑問に思いました。

これは正常に機能します。

-(void)viewDidLoad{
    [super viewDidLoad];
    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
}
-(void)runTimer{
    NSLog(@"hi");
}

しかし、これは機能しません:

dispatch_queue_t myQueue;

-(void)viewDidLoad{
    [super viewDidLoad];

    myQueue = dispatch_queue_create("someDescription", NULL);
    dispatch_async(myQueue, ^{
        [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
    });
}
-(void)runTimer{
    NSLog(@"hi");
}
4

3 に答える 3

62

NSTimersは、現在のスレッドの実行ループでスケジュールされます。ただし、GCDディスパッチスレッドには実行ループがないため、GCDブロックでタイマーをスケジュールしても何も起こりません。

3つの合理的な選択肢があります。

  1. タイマーをスケジュールする実行ループを見つけて、明示的に実行します。を使用+[NSTimer timerWithTimeInterval:target:selector:userInfo:repeats:]してタイマーを作成し、使用-[NSRunLoop addTimer:forMode:]する実行ループで実際にタイマーをスケジュールします。これには、問題の実行ループにハンドルが必要ですが+[NSRunLoop mainRunLoop]、メインスレッドで実行する場合にのみ使用できます。
  2. タイマーベースのディスパッチソースの使用に切り替えます。これにより、GCD対応メカニズムにタイマーが実装され、選択したキューで必要な間隔でブロックが実行されます。
  3. タイマーを作成する前に、明示的dispatch_async()にメインキューに戻ります。これは、メイン実行ループを使用するオプション#1と同等です(メインスレッドにタイマーも作成されるため)。

もちろん、ここでの本当の問題は、なぜ最初にGCDキューからタイマーを作成するのかということです。

于 2012-05-09T19:39:04.763 に答える