如何立即从runloop中删除计时器

pra*_*epa 4 iphone objective-c grand-central-dispatch nsrunloop

我有一个在 5 秒内触发的计时器添加到全局队列中,尽管我在 2 秒后使其无效,运行循环直到 5 秒才会终止。在以下代码段中,backgroundTimer 是一个实例 var,而 run 是一个成员函数。以下代码有什么问题阻止了运行循环终止。

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    _backgroundTimer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(run) userInfo:nil repeats:NO];
    [ [NSRunLoop currentRunLoop] addTimer:_backgroundTimer forMode:NSRunLoopCommonModes];
    [[NSRunLoop currentRunLoop] run];

    NSLog(@"Run loop terminated");

});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [_backgroundTimer invalidate];
    _backgroundTimer=nil;

});
Run Code Online (Sandbox Code Playgroud)

ipm*_*mcc 5

这里的第一个问题是您的计时器被添加到某个任意后台线程的运行循环中。(即线程将由 GCD 创建来为后台队列提供服务)您可以这样做,但这有点没有意义。

除此之外,你说你想要发生的是让这个运行循环退出,但在该-run方法的文档中,它说如下:

从运行循环中手动删除所有已知的输入源和计时器并不能保证运行循环会退出。OS X 可以根据需要安装和删除额外的输入源,以处理针对接收者线程的请求。因此,这些源可以阻止运行循环退出。

如果您希望运行循环终止,则不应使用此方法。相反,使用其他 run 方法之一,并在循环中检查您自己的其他任意条件。

如果您想在计时器无效时退出它,您将需要自己旋转事件循环。例如:

while (_backgroundTimer.valid && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow: 0.1]]);
Run Code Online (Sandbox Code Playgroud)

这将在计时器失效后最多 0.1 (-epsilon) 秒退出运行循环。