0
votes

I have an unwind segue which takes a few seconds to complete while it saves images to disk. I want to display an activity indicator until the view is dismissed but the view doesn't update.

This is my function, which is called from the view controller before it's dismissed:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "saveRecord" {
        print("indicator")
        let indicator = UIActivityIndicatorView()
        indicator.frame = self.view.frame
        indicator.activityIndicatorViewStyle = .whiteLarge
        indicator.color = UIColor.blue
        indicator.hidesWhenStopped = true
        indicator.startAnimating()
        self.view.addSubview(indicator)
        self.view.layoutSubviews()
        print("laid out subviews")
    }
}

The two print statements execute, and the debugger shows that the indicator has been added to the main view as a subview, but it doesn't appear on screen. Am I missing something?

I know the position of the indicator isn't a problem because running the same code in viewDidLoad correctly shows it in the middle of the screen.

UPDATE

I've recreated the segue functions using a delegate and it's saving everything correctly, but the problem remains. Still no activity indicator.

@IBAction func saveRecord(_ sender: Any) {
    print("indicator")
    let indicator = UIActivityIndicatorView()
    indicator.frame = self.view.frame
    indicator.activityIndicatorViewStyle = .whiteLarge
    indicator.color = UIColor.blue
    indicator.hidesWhenStopped = true
    indicator.startAnimating()
    self.view.addSubview(indicator)
    self.view.layoutSubviews()
    print("laid out subviews")
    saveImages()
    print("saved images")
    self.delegate?.saveRecord(name: name!, category: category)
    print("saved record")
    self.navigationController?.popViewController(animated: true)
}

UPDATE 2

I'm really confused now! This starts the indicator:

@IBAction func saveRecord(_ sender: Any) {
    print("indicator")
    indicator.startAnimating()
    //saveImages()
    //print("images saved")
    //performSegue(withIdentifier: "saveRecord", sender: self)
}

but this doesn't:

@IBAction func saveRecord(_ sender: Any) {
    print("indicator")
    indicator.startAnimating()
    saveImages()
    print("images saved")
    performSegue(withIdentifier: "saveRecord", sender: self)
}
3
Have you called performSegue some where in your code?Ahmad F
Thanks Ahmad. Yes I've tried various ways of triggering the segue but I still get the same issue.Chris

3 Answers

1
votes

The problem is that the UI doesn't update until the saveRecord function has completed, but then the segue is called so the view controller is immediately dismissed. I solved it using dispatch queues - another new skill I've learned today!:

@IBAction func saveRecord(_ sender: Any) {
    indicator.startAnimating()
    DispatchQueue.global(qos: .userInitiated).async {
        self.saveImages()
        DispatchQueue.main.async {
            self.performSegue(withIdentifier: "saveRecord", sender: self)
        }
    }
}
0
votes

I think you should use popViewController instead of an unwind segue. Then you have more control with a custom function on the back button.

What you can do then is:

  • when you click on the back button (or save image button), add you indicator
  • then save the image
  • when the image is saved remove the indicator
  • pop the view controller
0
votes

You can't update your views in prepare(for:); the segue is already underway.

Rather than triggering the unwind segue directly from the UI element, trigger an action method that shows the activity indicator and performs the save and then calls performSegue(withIdentifier:"yourUnwindSegueIdentifier", sender:self) to actually perform the unwind.