21

我想知道是否有人可以解释为什么调度回主队列并创建一个重复NSTimer我必须将它添加到 RUN LOOP 因为它太火了?即使在使用时,performselectorOnMainThread我仍然必须将其添加到 RUN LOOP 以使其触发。

下面是我的问题的一个例子:

#define queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define mainqueue dispatch_get_main_queue()

- (void)someMethodBeginCalled
{
    dispatch_async(queue, ^{
        int x = 0;
        dispatch_async(mainqueue, ^(void){
            if([_delegate respondsToSelector:@selector(complete:)])
                [_delegate complete:nil];
        });
    });
}

- (void)compelete:(id)object
{
    [self startTimer];

    //[self performSelectorOnMainThread:@selector(startTimer) withObject:nil waitUntilDone:NO];
}

- (void)startTimer
{
    NSTimer timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(callsomethingelse) userInfo:nil repeats:YES];

    //NSDefaultRunLoopMode
    [[NSRunLoop currentRunLoop] addTimer:_busTimer forMode:NSRunLoopCommonModes];
}

编辑: 我相信我对这个问题的措辞很糟糕。如果我打电话,我想知道为什么 [[NSRunLoop currentRunLoop] addTimer:_busTimer forMode:NSRunLoopCommonModes];有必要。如果我不包括该行,则计时器不会触发。startTimersomeMethodBeginCalled

例如,如果我打电话startTimer,我可以删除线路,计时器将每 60 秒触发一次。viewDidLoadNSRunLoop

4

6 回答 6

22

以下是如何将 an 添加NSTimer到运行循环:

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSDefaultRunLoopMode];
于 2013-03-20T15:06:29.617 回答
19

您总是可以使用此方法:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(getBusLocation) userInfo:nil repeats:YES];

这将为您节省一行,因为它会自动将其添加到运行循环中。

于 2012-03-29T02:32:25.503 回答
4

因为,正如文档所说:

计时器与运行循环一起工作。要有效地使用计时器,您应该了解运行循环是如何运行的——请参阅 NSRunLoop 和线程编程指南。特别要注意的是,运行循环保留了它们的计时器,因此您可以在将计时器添加到运行循环后释放它。

这是 Apple 在为 NSTimer 编写代码时做出的设计决定(我相信他们有充分的理由这样做),我们无能为力。真的有那么重吗?

于 2012-03-29T02:03:42.797 回答
3

就像@sosborn 所说,NSTimers 依赖于NSRunLoops,并且由于 GCD 队列创建的线程没有运行循环,NSTimer因此不能很好地与GCD.

查看有关此问题的其他 StackOverflow 问题:在 GCD 串行队列上安排和使 NSTimers 无效是否安全?

为了解决这个问题,我实现了MSWeakTimerhttps ://github.com/mindsnacks/MSWeakTimer (并在上一次 WWDC 上由 libdispatch 工程师检查了实现!)

于 2013-09-07T01:24:33.483 回答
1

由于 GCD 队列创建没有运行循环的线程,因此不会调用 Timer 方法

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
   [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
       NSLog(@"Timer method from GCD main queue");
   }];

});

但是,当在主队列上调度时,将调用计时器方法,因为它将被添加到主线程运行循环中。

dispatch_async(dispatch_get_main_queue(), ^{
   [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
       NSLog(@"Timer method from GCD main queue");
   }];

});
于 2017-04-05T03:46:17.970 回答
0

在我的情况下,将计时器添加到运行循环中不起作用。我必须在主线程上创建计时器。我在 MultipeerConnectivity 委托中创建了这个线程。

    dispatch_async(dispatch_get_main_queue(), ^{
        self.timer = [NSTimer scheduledTimerWithTimeInterval:self.interval  invocation: self.invocation repeats:YES];
    });
于 2016-02-14T00:22:17.687 回答