将进度条添加到 UIAlertController 并显示更新 [英] Add Progress bar to UIAlertController with showing update
问题描述
我尝试在我的应用程序上添加进度条.我在 How to add Progress bar to UIAlertController? 上找到了问题,但是它没有显示如何更新进度条.我将代码简化如下,但它没有更新进度条(它只在进度完成后显示).我看多了什么?感谢您的帮助.
I try to add progress bar on my application. I found the question on How to add Progress bar to UIAlertController? but it didn't show how to update the progress bar. I simplify the code as below but it didn't update the progress bar (it shows only once the progress is completed). What did i over look? Thank you for your help.
override func viewDidLoad() {
super.viewDidLoad()
var topViewController = UIApplication.shared.delegate!.window!!.rootViewController!
while (topViewController.presentedViewController != nil){
topViewController = topViewController.presentedViewController!
}
DispatchQueue.main.async(execute: {
let alert = UIAlertController(title: "downloading", message: "pls wait", preferredStyle: .alert)
let progressBar = UIProgressView(progressViewStyle: .default)
progressBar.setProgress(0.0, animated: true)
progressBar.frame = CGRect(x: 10, y: 70, width: 250, height: 0)
alert.view.addSubview(progressBar)
topViewController.present(alert, animated: true, completion: nil)
var progress: Float = 0.0
repeat {
DispatchQueue.global(qos: .background).async(execute: {
progress += 0.01
print (progress)
DispatchQueue.main.async(flags: .barrier, execute: {
progressBar.setProgress(progress, animated: true)
})
})
} while progress < 1.0
})
}
推荐答案
代码中的所有调度队列可能会让你有点困惑:-)
One could get just a little confused by all those dispatch queues in your code :-)
我试着解释这个问题:
第一个(最外层) DispatchQueue.main.async
在主 (UI) 线程中执行.它创建 UIAlertController
,将 UIProgressView
填充到其中并显示对话框.然后它在主线程中执行一些时间关键的工作(repeat-while-loop).永远不要这样做,因为它阻塞主线程.由于主线程被阻塞,UI控件中没有反映任何更新,因此您看不到进度变化.
The first (outmost) DispatchQueue.main.async
is excecuted in the main (UI) thread.
It creates the UIAlertController
, stuffs the UIProgressView
into it and displays the dialog. Then it performs in the main thread some time-critial job (repeat-while-loop). Never do so, because it blocks the main thread.
Since the main thread is blocked, no updates are reflected in the UI controls, so you don't see progress changes.
因此,
- 我将时间关键工作项(重复循环)作为异步工作项放入全局队列(不是主队列)
- 在该工作项中,我会将进度条更新分派到主队列(在主线程中执行)
- 最后,当一切都完成后,我关闭了
UIAlertController
- I put the time critical work item (repeat loop) into the global queue (not the main queue) as an asynchronous work item
- Within that work item, I'll dispatch the progress bar updates into the main queue (to be executed in the main thread)
- At the end, when everything is done, I dismiss the
UIAlertController
当您的警报视图从诸如
viewDidLoad
或viewWillAppear
之类的方法显示时,您只需要 first Dispatch,例如从视图尚未显示的时间点开始.如果您从按钮回调或viewDidAppear
(例如视图可见)调用它,您可以跳过该外部 Dispatch.You only need the first Dispatch when your alert view is shown from a method like
viewDidLoad
orviewWillAppear
, e.g. from a point in time when the view isn't displayed yet. If you call it from a button callback, orviewDidAppear
(e.g. view is visible), you could just skip that outer Dispatch.给你 - 我也投入了一些睡眠时间并稍微修改了 GCD-Calls 以使用尾随闭包:
Here you go - I also put in some sleep time and modified the GCD-Calls a litte to use trailing closures:
override func viewDidLoad() { super.viewDidLoad() var topViewController = UIApplication.shared.delegate!.window!!.rootViewController! while (topViewController.presentedViewController != nil){ topViewController = topViewController.presentedViewController! } // Usage of GCD here is only necessary because it's called from // viewDidLoad. If called by viewDidAppear or some action callback, you // don't need it: DispatchQueue.main.async { let alert = UIAlertController(title: "downloading", message: "pls wait", preferredStyle: .alert) let progressBar = UIProgressView(progressViewStyle: .default) progressBar.setProgress(0.0, animated: true) progressBar.frame = CGRect(x: 10, y: 70, width: 250, height: 0) alert.view.addSubview(progressBar) topViewController.present(alert, animated: true, completion: nil) var progress: Float = 0.0 // Do the time critical stuff asynchronously DispatchQueue.global(qos: .background).async { repeat { progress += 0.1 Thread.sleep(forTimeInterval: 0.25) print (progress) DispatchQueue.main.async(flags: .barrier) { progressBar.setProgress(progress, animated: true) } } while progress < 1.0 DispatchQueue.main.async { alert.dismiss(animated: true, completion: nil); } } } }
这篇关于将进度条添加到 UIAlertController 并显示更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!