从调度

时间:2016-01-21 01:18:08

标签: ios multithreading swift uiprogressview

我试图让进度条充当计时器并从15秒倒计时,这是我的代码:

private var timer: dispatch_source_t!
private var timeRemaining: Double = 15

override public func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    profilePicture.layer.cornerRadius = profilePicture.bounds.width / 2

    let queue = dispatch_queue_create("buzz.qualify.client.timer", nil)
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 10 * NSEC_PER_MSEC, 5 * NSEC_PER_MSEC)
    dispatch_source_set_event_handler(timer) {
        self.timeRemaining -= 0.01;
        self.timerBar.setProgress(Float(self.timeRemaining) / 15.0, animated: true)
        print(String(self.timerBar.progress))
    }
    dispatch_resume(timer)
}

print()打印正确的结果,但进度条永远不会更新,有时它会在12-15%左右完成一次更新,只有JUMP然后再做其他事情。

如何使此栏稳定地向下流动,然后在计时器结束时执行任务而不阻止UI线程。

2 个答案:

答案 0 :(得分:6)

在siburb的回答中,他正确地指出应该确保在主线程上发生UI更新。

但是我有一个次要的观察,即你每秒进行100次更新,并且没有必要这么做,因为最大屏幕刷新率是每秒60帧。

然而,显示链接就像一个计时器,除了它链接到屏幕刷新率。你可以这样做:

var displayLink: CADisplayLink?
var startTime: CFAbsoluteTime?
let duration = 15.0

func startDisplayLink() {
    startTime = CFAbsoluteTimeGetCurrent()
    displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:")
    displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}

func stopDisplayLink() {
    displayLink?.invalidate()
    displayLink = nil
}

func handleDisplayLink(displayLink: CADisplayLink) {
    let percentComplete = Float((CFAbsoluteTimeGetCurrent() - startTime!) / duration)
    if percentComplete < 1.0 {
        self.timerBar.setProgress(1.0 - percentComplete, animated: false)
    } else {
        stopDisplayLink()
        self.timerBar.setProgress(0.0, animated: false)
    }
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    startDisplayLink()
}

或者,如果你在后台线程上做某事想要比UIProgressView发布更新比主线程可以为它们服务更快,那么我会使用调度源将其发布到主线程输入DISPATCH_SOURCE_TYPE_DATA_ADD

但是,如果你只是想在一段固定的时间内更新进度视图,那么显示链接可能比定时器更好。

答案 1 :(得分:2)

您必须始终更新主线程上的UI。我不是Swift专家,但看起来你正在尝试在后台更新UIProgressView

尝试更新主队列上的UIProgressView,如下所示:

dispatch_async(dispatch_get_main_queue(),^{
    self.timerBar.setProgress(Float(self.timeRemaining) / 15.0, animated: true)
    print(String(self.timerBar.progress))
})