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
})
}
After help from Andreas comment. I work out with this code.
One could get just a little confused by all those dispatch queues in your code :-)
I try to explain the problem:
The first (outmost)
DispatchQueue.main.async
is excecuted in the main (UI) thread. It creates theUIAlertController
, stuffs theUIProgressView
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.Therefore,
UIAlertController
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.Here you go - I also put in some sleep time and modified the GCD-Calls a litte to use trailing closures: