您+[NSTimer scheduledTimerWithTimeInterval:...]
从 GCD 工作线程调用。GCD 工作线程不运行运行循环。这就是为什么你的第一次尝试没有奏效。
当您尝试时[[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode]
,您正在从 GCD 工作线程向主运行循环发送消息。存在的问题NSRunLoop
不是线程安全的。(这在NSRunLoop 类参考中有记录。)
相反,您需要分派回主队列,以便当您将addTimer:...
消息发送到主运行循环时,它在主线程上完成。
-(void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSTimer *timer = [NSTimer timerWithTimeInterval:0.10
target:self
selector:@selector(action_Timer)
userInfo:nil
repeats:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
});
});
}
实际上,如果您要在主运行循环中安排它,则没有理由在后台队列上创建计时器。您可以直接分派回主队列来创建和调度它:
-(void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"on background queue");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"on main queue");
[NSTimer scheduledTimerWithTimeInterval:0.10
target:self
selector:@selector(action_Timer)
userInfo:nil
repeats:YES];
});
});
}
请注意,我的两个解决方案都将计时器添加到主运行循环中,因此计时器的操作将在主线程上运行。如果您希望计时器的操作在后台队列上运行,您应该从操作中分派给它:
-(void)action_Timer {
// This is called on the main queue, so dispatch to a background queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
LOG("Timer called");
});
}