【问题标题】:iOS: UILabel countdown hangs on other UI operationiOS:UILabel 倒计时挂在其他 UI 操作上
【发布时间】:2013-03-10 10:56:26
【问题描述】:

我正在实现一个倒计时,它的值显示在 UILabel 上,但遇到了问题。这是简化的代码:

self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countdown) userInfo:nil repeats:YES];

- (void)countdown {          
     self.countdownLabel.text = [NSString stringWithFormat:@"%i",[self.countdownLabel.text intValue]-1];

     // Handle time out
     if ([self.countdownLabel.text intValue] == 0) {
             [self.countdownTimer invalidate];
             self.countdownTimer = nil;
     }
}

它工作正常,但是如果我在视图控制器中执行其他 UI 操作,例如滚动滚动视图,计时器会在滚动视图滚动时挂起,然后加速以弥补空闲时间。

我尝试将标签的更新分派到后台队列,这当然不起作用。

dispatch_queue_t bgQ = dispatch_queue_create("bgQ", 0);
dispatch_async(bgQ, ^{
    self.countdownLabel.text = [NSString stringWithFormat:@"%i",[self.countdownLabel.text intValue]-1];
});

这里的解决方案是什么?

【问题讨论】:

  • UIKit 应该总是在主线程上调用。
  • 我知道,只是想要一个肮脏的解决方案......但我该如何让它不会挂起?
  • NSTimer 插入运行循环,由 UIScrollView 接管(为了优化,它做了一些平铺和小技巧。不幸的是,确实没有一个好的方法来做到这一点。我d 只是忍受它,因为它是在您当前情况下的每个应用程序中发现的行为(Tweetbot、Twitterific 和 Netbot 似乎都有这个问题)。
  • @Zoltán 引用我自己的话:“UIKit 应该总是在主线程上调用。”
  • @CodaFi 哇我还以为这是小事

标签: ios objective-c multithreading uilabel countdown


【解决方案1】:
self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countdown) userInfo:nil repeats:YES];    
[[NSRunLoop mainRunLoop] addTimer:self.countdownTimer forMode:NSRunLoopCommonModes];

请记住,在您的倒计时方法中,您需要一个转义来使您的倒计时计时器无效。

定时器将在没有触发指令的情况下启动

[[NSRunLoop mainRunLoop] addTimer:self.countdownTimer forMode:NSRunLoopCommonModes];

行被执行。 绝对没有针对 UI 更改的异步调度。

希望这会有所帮助。

【讨论】:

  • 嗯,你可以 dispatch_async 到主线程。并非在所有情况下都被禁止。
  • 嘿,这很好用,谢谢!我有 // 处理超时 if ([self.countdownLabel.text intValue] == 0) { [self.countdownTimer invalidate]; self.countdownTimer = nil;在倒计时方法中,这应该足以使其无效。当我使计时器无效时,我是否需要对 runloop 做一些事情?
  • 是的 CodaFi,我的意思是永远不要在不同于主队列的队列上异步。
【解决方案2】:

Swift 3.0 语法

var timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(ViewController.updateTimer), userInfo: nil, repeats: true);
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)

【讨论】:

    猜你喜欢
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    相关资源
    最近更新 更多