从调度更新时,UIProgressView 不会更新进度
UIProgressView won't update progress when updated from a dispatch
我正在尝试让进度条充当计时器并从 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% 满时进行一次更新,然后只跳到那里,然后什么都不做。
怎样才能让这个条稳定的往下流,然后在定时器结束的时候执行一个任务而不阻塞UI线程
您必须始终在主线程上更新 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))
})
在 siburb 的回答中,他正确地指出应该确保 UI 更新发生在主线程上。
但我有一个次要观察结果,即您每秒进行 100 次更新,这样做没有意义,因为最大屏幕刷新率为每秒 60 帧。
但是,显示器 link 就像一个计时器,只不过它 link 设置为屏幕刷新率。你可以这样做:
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()
}
或者,如果您在后台线程上执行某些操作,希望 post 更新到 UIProgressView
的速度快于主线程可以为它们提供服务的速度,那么我会 post使用 DISPATCH_SOURCE_TYPE_DATA_ADD
.
类型的调度源到主线程
但是,如果您只是想在某个固定时间段内更新进度视图,显示 link 可能比计时器更好。
我正在尝试让进度条充当计时器并从 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% 满时进行一次更新,然后只跳到那里,然后什么都不做。
怎样才能让这个条稳定的往下流,然后在定时器结束的时候执行一个任务而不阻塞UI线程
您必须始终在主线程上更新 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))
})
在 siburb 的回答中,他正确地指出应该确保 UI 更新发生在主线程上。
但我有一个次要观察结果,即您每秒进行 100 次更新,这样做没有意义,因为最大屏幕刷新率为每秒 60 帧。
但是,显示器 link 就像一个计时器,只不过它 link 设置为屏幕刷新率。你可以这样做:
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()
}
或者,如果您在后台线程上执行某些操作,希望 post 更新到 UIProgressView
的速度快于主线程可以为它们提供服务的速度,那么我会 post使用 DISPATCH_SOURCE_TYPE_DATA_ADD
.
但是,如果您只是想在某个固定时间段内更新进度视图,显示 link 可能比计时器更好。