swiftzipprogress-barswift4hud

How to show progress hud while compressing a file in Swift 4?


I'm using marmelroy/Zip framework to zip/unzip files in my project, and JGProgressHUD to show the progress of the operation.

I'm able to see the HUD if I try to show it from the ViewDidLoad method, but if I use it in the closure associated to the progress feature of the quickZipFiles method (like in the code sample), the hud is shown just at the end of the operation.

I guess this could be related to a timing issue, but since I'm not too much into completion handlers, closures and GDC (threads, asynchronous tasks, etc.) I would like to ask for a suggestion.

Any ideas?

// In my class properties declaration
var hud = JGProgressHUD(style: .dark)

// In my ViewDidLoad
self.hud.indicatorView = JGProgressHUDPieIndicatorView()
self.hud.backgroundColor = UIColor(white: 0, alpha: 0.7)

// In my method
do {
    self.hud.textLabel.text = NSLocalizedString("Zipping files...", comment: "Zipping File Message")
    self.hud.detailTextLabel.text = "0%"
    if !(self.hud.isVisible) {
        self.hud.show(in: self.view)
    }
    zipURL = try Zip.quickZipFiles(documentsList, fileName: "documents", progress: { (progress) -> () in
        let progressMessage = "\(round(progress*100))%"
        print(progressMessage)
        self.hud.setProgress(Float(progress), animated: true)
        self.hud.textLabel.text = NSLocalizedString("Zipping files...", comment: "Zipping File Message")
        self.hud.detailTextLabel.text = progressMessage
        if (progress == 1.0) {
            self.hud.dismiss()
        }
    })
} catch {
    print("Error while creating zip...")
}

Solution

  • Looking at the implementation of the zip library, all of the zipping/unzipping and the calls to the progress handlers are being done on the same thread. The example shown on the home page isn't very good and can't be used as-is if you wish to update the UI with a progress indicator while zipping or unzipping.

    The solution is to perform the zipping/unzipping in the background and in the progress block, update the UI on the main queue.

    Assuming you are calling your posted code from the main queue (in response to the user performing some action), you should update your code as follows:

    // In my class properties declaration
    var hud = JGProgressHUD(style: .dark)
    
    // In my ViewDidLoad
    self.hud.indicatorView = JGProgressHUDPieIndicatorView()
    self.hud.backgroundColor = UIColor(white: 0, alpha: 0.7)
    
    self.hud.textLabel.text = NSLocalizedString("Zipping files...", comment: "Zipping File Message")
    self.hud.detailTextLabel.text = "0%"
    if !(self.hud.isVisible) {
        self.hud.show(in: self.view)
    }
    
    DispatchQueue.global().async {
        defer {
            DispatchQueue.main.async {
                self.hud.dismiss()
            }
        }
    
        do {
            zipURL = try Zip.quickZipFiles(documentsList, fileName: "documents", progress: { (progress) -> () in
                DispatchQueue.main.async {
                    let progressMessage = "\(round(progress*100))%"
                    print(progressMessage)
                    self.hud.setProgress(Float(progress), animated: true)
                    self.hud.textLabel.text = NSLocalizedString("Zipping files...", comment: "Zipping File Message")
                    self.hud.detailTextLabel.text = progressMessage
                }
            })
        } catch {
            print("Error while creating zip...")
        }
    }