【问题标题】:How update a label periodically on iOS (every second)? [duplicate]如何在 iOS 上定期更新标签(每秒)? [复制]
【发布时间】:2011-06-03 16:11:51
【问题描述】:

我使用每秒触发一次的 NSTimer 并更新一个显示事件前剩余时间的标签。

到目前为止我工作得很好。问题是当我滚动 TableView 时,我的标签没有更新,因为 MainThread 被触摸/滚动事件阻塞。

我曾考虑为 Timer 创建第二个线程,但无论如何我无法从后台线程更新标签。我不得不将它与 performSelector... 放在 MainThread 上,它会像以前一样卡住。

有没有办法在滚动时更新标签?

【问题讨论】:

标签: iphone uikit


【解决方案1】:

问题是在主线程跟踪触摸时不会调用 scheduleTimer。您需要在主运行循环中安排计时器。

所以不要这样做

[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLabel:) userInfo:nil repeats:YES];

使用

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

【讨论】:

  • 我认为 scheduleTimerWithTimeInterval 将它添加到当前运行循环中,即 mainRunLoop,因为我的应用程序是单线程的。
  • NSRunLoopCommonModes 会让你的计时器在表格视图跟踪你的触摸时仍然被调用。
  • @Alexander:它将它添加到 default 运行循环模式中,并非所有模式都被视为 common 运行循环模式。在触摸跟踪期间,运行循环在默认模式以外的其他模式下运行,因此不会检查您的计时器。
  • NSRunLoopCommonMods 上的错字?应该是NSRunLoopCommonModes
  • 谢谢,这里转换为 ruby​​motion 使用 timer = NSTimer.timerWithTimeInterval(1.0,target:self,selector:'updateLabel',userInfo:nil,repeats:true) NSRunLoop.mainRunLoop.addTimer(timer,forMode:NSRunLoopCommonModes)
【解决方案2】:

试试这个:

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

【讨论】:

    【解决方案3】:

    可以也使用 GCD。所以运行

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLabel:) userInfo:nil repeats:YES];
    });
    

    现在在你的 updateLabel 方法中

    - (void) updateLabel:(id) sender {
        NSString *text = @"some text";
        dispatch_sync(dispatch_get_main_queue(), ^{
            label.text = text;
        });
    }
    

    这将更新主线程中的标签。

    【讨论】:

    • 那是灾难的根源。计时器在高优先级并发队列决定使用的任何随机(可能是临时)线程的运行循环中注册,这意味着它可能永远不会有机会触发。如果您想在 GCD 中使用延迟,请使用 dispatch_after。在这种情况下,您可以将其设置为在 1 秒后将块分派到主队列。
    • hrmm... 是的,我想这是有道理的。在那种情况下,调度代码会是什么样子?
    • 参见例如gist.github.com/1006912。注释是编写代码的好地方。
    • 这是解决这个问题的错误方法。我开发了同样的东西并卡住了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 2013-02-25
    相关资源
    最近更新 更多