用GCD运行重复NSTimer?

我想知道为什么当你在GCD块中创build一个重复定时器时,它不工作?

这工作正常:

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

NSTimers被安排在当前线程的运行循环中 。 但是,GCD调度线程没有运行循环,因此在GCD块中调度定时器不会做任何事情。

有三个合理的select:

  1. 找出你想要安排定时器的运行循环,明确地这样做。 使用+[NSTimer timerWithTimeInterval:target:selector:userInfo:repeats:]来创build计时器,然后-[NSRunLoop addTimer:forMode:]实际将其安排在您要使用的运行循环上。 这需要在运行循环中有一个句柄,但是如果你想在主线程上执行,你可以使用+[NSRunLoop mainRunLoop]
  2. 切换到使用基于计时器的调度源 。 这实现了一个GCD感知机制中的计时器,它将按照您希望在您select的队列上的间隔运行一个块。
  3. 在创build计时器之前,显式地dispatch_async()返回到主队列。 这相当于使用主运行循环的选项#1(因为它也会在主线程上创build定时器)。

当然,这里真正的问题是,为什么从GCD队列创build一个定时器开始?

这是一个坏主意 。 我即将删除这个答案,但我把它留在这里,以避免别人做我犯的同样的错误。 谢谢#Kevin_Ballard指出这一点。

你只需要在你的例子中添加一行,就像你写的那样:

[[NSRunLoop currentRunLoop] run]

所以你会得到:

  -(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]; [[NSRunLoop currentRunLoop] run] }); } 

由于你的队列myQueue包含一个NSThread,并且它包含一个NSRunLoop,并且由于dispatch_async的代码运行了该NSThread的上下文, currentRunLoop将返回与你的队列的线程关联的一个停止的运行循环。