将进度条添加到 UIAlertController 并显示更新
Add Progress bar to UIAlertController with showing update
我尝试在我的应用程序中添加进度条。我在 How to add Progress bar to UIAlertController? 上找到了问题,但它没有显示如何更新进度条。我将代码简化如下,但它没有更新进度条(它只在进度完成后显示)。我看了什么?感谢您的帮助。
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
})
}
您的代码中的所有这些调度队列可能会让您感到有点困惑:-)
我试着解释问题:
第一个(最外面) DispatchQueue.main.async
在主(UI)线程中执行。
它创建 UIAlertController
,将 UIProgressView
填充到其中并显示对话框。然后它在主线程中执行 一些 time-critial 作业 (repeat-while-loop)。永远不要这样做,因为它 阻塞 主线程。
由于主线程被阻塞,UI 控件中没有反映任何更新,因此您看不到进度变化。
因此,
- 我将time critical工作项(重复循环)作为异步工作放入global队列(不是主队列)物品
- 在该工作项中,我会将进度条更新分派到主队列(在主线程中执行)
- 最后,当一切都完成后,我关闭
UIAlertController
当您的警报视图通过 viewDidLoad
或 viewWillAppear
等方法显示时,您只需要 first 调度,例如从尚未显示视图的时间点开始。如果您从按钮回调或 viewDidAppear
(例如视图可见)调用它,您可以跳过外部 Dispatch。
给你 - 我也投入了一些睡眠时间并修改了 GCD-Calls 一点点以使用尾随闭包:
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);
}
}
}
}
在 Andreas 评论的帮助下。我用这段代码锻炼。
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: "loading", message: "wait please", preferredStyle: .alert)
let rect = CGRect(x: 10, y: 70, width: 250, height: 0)
let progressView = UIProgressView(frame: rect)
progressView.progress = 0.0
progressView.tintColor = UIColor.blue
alert.view.addSubview(progressView)
topViewController.present(alert, animated: true, completion: nil)
var progress = 0.0
DispatchQueue.global(qos: .background).async(execute: {
repeat {
progress += 0.0001
print (progress)
DispatchQueue.main.async(flags: .barrier, execute: {
progressView.progress = Float(progress)
})
} while progress < 1.0
DispatchQueue.main.async(execute: {
alert.dismiss(animated: true, completion: nil);
})
})
})
}
我尝试在我的应用程序中添加进度条。我在 How to add Progress bar to UIAlertController? 上找到了问题,但它没有显示如何更新进度条。我将代码简化如下,但它没有更新进度条(它只在进度完成后显示)。我看了什么?感谢您的帮助。
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
})
}
您的代码中的所有这些调度队列可能会让您感到有点困惑:-)
我试着解释问题:
第一个(最外面) DispatchQueue.main.async
在主(UI)线程中执行。
它创建 UIAlertController
,将 UIProgressView
填充到其中并显示对话框。然后它在主线程中执行 一些 time-critial 作业 (repeat-while-loop)。永远不要这样做,因为它 阻塞 主线程。
由于主线程被阻塞,UI 控件中没有反映任何更新,因此您看不到进度变化。
因此,
- 我将time critical工作项(重复循环)作为异步工作放入global队列(不是主队列)物品
- 在该工作项中,我会将进度条更新分派到主队列(在主线程中执行)
- 最后,当一切都完成后,我关闭
UIAlertController
当您的警报视图通过 viewDidLoad
或 viewWillAppear
等方法显示时,您只需要 first 调度,例如从尚未显示视图的时间点开始。如果您从按钮回调或 viewDidAppear
(例如视图可见)调用它,您可以跳过外部 Dispatch。
给你 - 我也投入了一些睡眠时间并修改了 GCD-Calls 一点点以使用尾随闭包:
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);
}
}
}
}
在 Andreas 评论的帮助下。我用这段代码锻炼。
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: "loading", message: "wait please", preferredStyle: .alert)
let rect = CGRect(x: 10, y: 70, width: 250, height: 0)
let progressView = UIProgressView(frame: rect)
progressView.progress = 0.0
progressView.tintColor = UIColor.blue
alert.view.addSubview(progressView)
topViewController.present(alert, animated: true, completion: nil)
var progress = 0.0
DispatchQueue.global(qos: .background).async(execute: {
repeat {
progress += 0.0001
print (progress)
DispatchQueue.main.async(flags: .barrier, execute: {
progressView.progress = Float(progress)
})
} while progress < 1.0
DispatchQueue.main.async(execute: {
alert.dismiss(animated: true, completion: nil);
})
})
})
}