ios - 为什么我不能停止 dispatch_async 串行队列中的计时器?

标签 ios grand-central-dispatch nstimer

这只是一个实验代码,但我很困惑,因为代码没有按我预期的那样执行。

代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.myQueue = dispatch_queue_create("com.maxwell.timer", NULL);
    dispatch_async(self.myQueue, ^{
        self.timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
            NSLog(@"Hey!");
        }];
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
    });
}

现在,我得到了一个输出“嘿!”每 1 秒一次,这里没问题。我知道在分派(dispatch)的线程中我必须显式运行 runloop。

当我试图停止计时器时,问题出现了。

- (void)stopTimer { 
    dispatch_async(self.myQueue, ^{
        [self.timer invalidate];
        self.Timer = nil;
    });
}

实际上 block 中的代码甚至不会执行!

另外,如果我这里使用并发队列(dispatch_asyn(dispatch_get_global_queue(...), ^{...}))就可以了。

我知道的事情:每次我dispatch_async,无论并发队列还是串行队列,代码都在不同的线程中执行。所以严格来说,我没有在我添加它的同一线程中使计时器失效,但它确实在并发线程中失效。

所以我的问题是为什么它在串行队列中无法失效?

最佳答案

问题是您有一个串行队列,您可以在该队列上调用 [[NSRunLoop currentRunLoop] run] .但是您不会从该调用返回(只要该运行循环上有计时器等)。作为run documentation说:

If no input sources or timers are attached to the run loop, this method exits immediately; otherwise, it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate:. In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers.

这会阻塞串行队列的线程。只要该线程被阻塞,分派(dispatch)到该队列的任何代码(例如您尝试使计时器无效)都不会运行。你有一个“第 22 条军规”。

最重要的是,如果您要设置后台线程来运行 NSTimer,您需要为此创建自己的线程,而不是使用 GCD worker线程。参见 https://stackoverflow.com/a/38031658/1271826举个例子。但正如该答案继续描述的那样,在后台线程上运行计时器的首选方法是调度计时器,让您摆脱操纵线程和运行循环的杂草。

关于ios - 为什么我不能停止 dispatch_async 串行队列中的计时器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52315181/

相关文章:

ios - 将 Swift 的调用同步到基于 C 的线程不安全库

swift - Swift 4 中的多线程 for 循环

ios - 我在游戏中使用计时器,想显示当前分数并保存最高分。我该怎么做?

ios - 定时器更新标签比第二个定时器倒计时晚 1 秒

ios - 使用 AVPlayer 流式传输音频

ios - 处理到 App Store 后立即下架

iphone - 如何处理大 JSON 响应

ios - 在 ios 9 中设置应用角标(Badge)编号

ios - 当 Swift 中的 WiFi 可用时,恢复线程时遇到问题

ios - 在 Swift 中使用 NSTimer 查找选择器时出错