Search code examples
iosswiftuiviewcontrollernsoperationqueue

Why isn't label.text update reflected on screen?


I have a simple test app that submits a few jobs to a NSOperationQueue, then waits for them to finish. I then have a routine that checks the number of jobs in the queue and is supposed to update a value on screen. At the same time it prints the value to the console. The console works exactly as I would expect with a number being printed every ten seconds. The number reduces to zero and the alert is fired. But at no stage does the label (progress) ever change from "Hello".

I have a feeling that rather than being a bug in my code it is a gaping hole in my understanding of Swift. Please help.

My code:

Import UIKit

class TestUpload: UIViewController {


@IBOutlet weak var progress: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
    progress.text = "Hello"

    // submit some jobs ….        
    // * I have omitted this code as I don't think it has a problem. * //

    let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 10 * Int64(NSEC_PER_SEC))
    dispatch_after(time, dispatch_get_main_queue()) {

        self.showProgress()
    }

}

func showProgress() {

    while Int(session.operationQueue.operationCount) > 0 {
        sleep(10)
        print(session.operationQueue.operationCount)
        progress.text = String(session.operationQueue.operationCount)
    }

    let confirmUpload = UIAlertController(title: "Your Tasks have been performed.", message: "Congratulation!", preferredStyle: UIAlertControllerStyle.Alert)
    confirmUpload.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { (action: UIAlertAction!) in  self.navigationController?.popViewControllerAnimated(true)}))

    presentViewController(confirmUpload, animated: true, completion: nil)


}

Solution

  • UI wont be updated until end of showProgress method. So you can do something like below if that's what you after,.

    call as a different thread,

    NSThread.detachNewThreadSelector("showProgress", toTarget: self, withObject: nil)
    

    and then update UI on main thread

    func showProgress() {
    
        while Int(session.operationQueue.operationCount) > 0 {
            sleep(10)
            print(session.operationQueue.operationCount)
    
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                progress.text = String(session.operationQueue.operationCount)
            })
        }
    
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
        let confirmUpload = UIAlertController(title: "Your Tasks have been performed.”, message: “Congratulation!”, preferredStyle: UIAlertControllerStyle.Alert)
            confirmUpload.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { (action: UIAlertAction!) in  self.navigationController?.popViewControllerAnimated(true)}))
    
            presentViewController(confirmUpload, animated: true, completion: nil)
        })
    
    
    }
    

    running both in main thread wont solve your problem even if you make it async dispatch