将进度条添加到 UIAlertController 并显示更新 [英] Add Progress bar to UIAlertController with showing update

查看:141
本文介绍了将进度条添加到 UIAlertController 并显示更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试在我的应用程序上添加进度条.我在 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

      当您的警报视图从诸如 viewDidLoadviewWillAppear 之类的方法显示时,您只需要 first Dispatch,例如从视图尚未显示的时间点开始.如果您从按钮回调或 viewDidAppear(例如视图可见)调用它,您可以跳过该外部 Dispatch.

      You only need the first Dispatch when your alert view is shown from a method like viewDidLoad or viewWillAppear, e.g. from a point in time when the view isn't displayed yet. If you call it from a button callback, or viewDidAppear (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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆