2017-01-27 2 views
0

Я пытаюсь добавить индикатор выполнения в моем приложении. Я нашел вопрос на How to add Progress bar to UIAlertController?, но он не показывал, как обновить индикатор выполнения. Я упрощаю код, как показано ниже, но он не обновлял индикатор выполнения (он отображается только после завершения выполнения). Что я на самом деле посмотрел? Спасибо за помощь.Добавить индикатор выполнения в 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 
    }) 
} 
+0

Как быстро выполняется этот цикл выполнения? Вы видите, что печатный прогресс медленно нарастает, или все цифры появляются во вспышке? добавьте немного задержки там, загрузите файл или что-то еще, и посмотрите, как это выглядит. – Russell

ответ

2

можно было получить только немного смущены все эти очереди отправки в вашем коде :-)

Я пытаюсь объяснить проблему:

первый (первейшая)DispatchQueue.main.async является та или иная строчка в основном (UI) потоке. Он создает UIAlertController, наполняет его UIProgressView и отображает диалоговое окно. Затем он выполняет в основной теме некоторое временное задание (повтор-в-цикле). Никогда не делайте этого, потому что он блокирует основной поток. Поскольку основной поток заблокирован, в элементах управления пользовательского интерфейса не отображаются обновления, поэтому вы не видите изменений в ходе выполнения.

Поэтому

  • Я положил время критического рабочий элемент в (повтор цикла) в глобальной очереди (не основной очереди) в качестве асинхронного элемента
    • работы В рамках этой работы item, я отправлю обновления обновлений в основную очередь (будет выполняться в основной теме)
    • В конце, когда каждый нг сделано, я уволить UIAlertController

Вам нужно только первый Отправка когда ваше предупреждение вид показан из метода как viewDidLoad или viewWillAppear, например, с момента, когда представление еще не отображается. Если вы вызываете это из обратного вызова кнопки или viewDidAppear (например, вид виден), вы можете просто пропустить эту внешнюю отправку.

Здесь вы идете - я также положить в какое-то время сна и модифицирована НОД-Вызывает Litte использовать хвостовые затворов:

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); 
      } 
     } 
    } 
} 
+0

Спасибо, Андреас. Ваш код работает как волшебство. Я поставил свой код ниже как код с некоторой рабочей нагрузкой (а не сном). –

0

После помощи от 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); 
      }) 
     }) 

    }) 
} 
Смежные вопросы