2

我使用更新标签的 NSTimer 编写了一个计时器。问题是,在同一个视图控制器中,我有一个 uitableview,当我向下滚动它时,计时器不会更新它的值,因此用户可以“作弊”来停止计时器。

我认为这可以很容易地通过带有 CGD 的串行队列来解决,但我不知道该怎么做。

提前致谢,

胡安

4

4 回答 4

4

首先请记住,除了主线程之外,您不能在任何其他线程中执行 UI 更改。话虽如此,您需要NSTimer在主队列中触发,否则程序会在更改UILabel. 看看这个链接http://bynomial.com/blog/?p=67和这个http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSRunLoop_Class/参考/Reference.html

据我所知,如果您在 for 中安排计时器,NSRunLoopCommonModes它将忽略事件更新并按照您的需要触发计时器:

 NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
                                           target:self
                                         selector:@selector(timerDidTick:)
                                         userInfo:nil repeats:YES];
  [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

-(void) timerDidTick:(NSTimer*) theTimer{
    [[self myLabel] setText:@"Timer ticked!"];
}
于 2013-04-28T10:03:36.400 回答
0

如果您在主线程中运行计时器而不是滚动 tableview 其停止计时器时,我遇到了同样的问题。解决方案是您在后台运行计时器并在主线程中更新 GUI

    UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //run function methodRunAfterBackground
    updateTimer1=[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateGUIAudioPlayer) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:updateTimer1 forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
});

    -(void)updateGUIAudioPlayer {
dispatch_async(dispatch_get_main_queue(), ^{
    self.label.text = @"your text";
});

    //but if you want to stop timer by himself than use main thread too like that

    dispatch_async(dispatch_get_main_queue(), ^{
             [updateTimer1 invalidate];
         });}
于 2015-06-12T07:22:09.903 回答
0
-(void) timerDidTick:(NSTimer*) theTimer{
        _currentNumber =_currentNumber+1;
        //check if current number is bigger than the contents of the word array
        if (_currentNumber <=wordArray.count-1) {
            NSLog(@"_currentNumber @%i wordArray @%i",_currentNumber,wordArray.count);
            _RandomLoadingText.text = @"Timer" ;
            [self changeTextInRandomLoadingLabel:_currentNumber];
        }

        else if (_currentNumber >=wordArray.count-1)
         {
             NSLog(@"reached end of array");
             [timer invalidate];
         }
    }

-(void)changeTextInRandomLoadingLabel:(int)myInt
{
    _RandomLoadingText.text = [wordArray objectAtIndex:myInt];
}

//--------- 视图已加载

    _RandomLoadingText.text = @"Test";
    _currentNumber =0;
    timer = [NSTimer timerWithTimeInterval:1.0
                                             target:self
                                           selector:@selector(timerDidTick:)
                                           userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
于 2016-10-04T15:13:51.850 回答
0

要更新 UI,您需要使用OperationQueue.main. 假设你有一个UILabel命名的 timeLabel:

var timeInSeconds = 0

timer = Timer(timeInterval: 1, repeats: true, block: { timer in
        timeInSeconds += 1
        OperationQueue.main.addOperation {
            self.timeLabel.text = String(timeInSeconds)
        }
    })

RunLoop.main.add(timer, forMode: .commonModes)
于 2018-03-16T09:52:06.933 回答