1

I'm trying to show a spinner during a possibly lengthy action invoked by a button press, but I can't get it to show up. Here's my code:

class ViewController: UIViewController {

   var actInd : UIActivityIndicatorView!
   [...]

   override func viewDidLoad() {

      super.viewDidLoad()

      self.actInd = UIActivityIndicatorView(frame: CGRectMake(0,0, 50, 50)) as UIActivityIndicatorView

      self.actInd.center = view.center
      self.actInd.hidesWhenStopped = true
      self.actInd.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
      self.view.addSubview(actInd)

      [...]
    }

    @IBAction func buttonPressed(sender: UIBarButtonItem) {
        self.actInd.startAnimating()
        // [...] do some work
        self.actInd.stopAnimating()
    }
}

It looks to me like the animation doesn't get shown when started from within the UI thread executing the button pressed (if I only start the animation in the button call without stopping, it starts to display as soon as the buttonPressed callback finishes). I tried to play around with dispatch_async but didn't get anywhere. Here's what I tried:

First:

    @IBAction func buttonPressed(sender: UIBarButtonItem) {

        dispatch_async(dispatch_get_main_queue()) {
            self.actInd.startAnimating()
        }
        shufflePlaylist()
        dispatch_async(dispatch_get_main_queue()) {
            self.actInd.stopAnimating()
        }
    }

Second:

    @IBAction func buttonPressed(sender: UIBarButtonItem) {

        dispatch_async(dispatch_get_main_queue()) {
            shufflePlaylist()
        }
    }

    func shufflePlaylist() {

        self.actInd.startAnimating()
        // [...] do the work
        self.actInd.stopAnimating()
    }

Third:

    @IBAction func buttonPressed(sender: UIBarButtonItem) {

        self.actInd.startAnimating()

        dispatch_async(dispatch_get_main_queue()) {
            shufflePlaylist()
        }
    }

    func shufflePlaylist() {

        // [...] do the work
        self.actInd.stopAnimating()
    }

I run into the same problem when trying to show the spinner after the user deletes a table view row in (which also can trigger some lengthy data update operation) in commitEditingStyle.

So what's the right approach to show an activity indicator in those cases?

2
  • What exactly is happening between the start and the stop calls? From what you've posted it seems likely that the spinner is starting and immediately stopping because the 'do some work' call is asynchronous. You mentioned you've tried using dispatch_async - can you show what you tried. Normal practice would be to dispatch to a worker queue, execute the action required synchronously, and then dispatch back to the main queue to stop the spinner - this tutorial might be helpful Commented Jan 17, 2016 at 18:42
  • The 'do some work' is actually all happening synchronously within the same thread (it's doing some computation and re-sorting the data source of the table view). I've updated my post with what I've tried using dispatch_async Commented Jan 17, 2016 at 20:20

1 Answer 1

1

What you want is something like:

@IBAction func buttonPressed(sender: UIBarButtonItem) {
  spinner.startAnimating()
  let dispatchPriority = DISPATCH_QUEUE_PRIORITY_DEFAULT
  dispatch_async(dispatch_get_global_queue(dispatchPriority, 0)) { 

    NSThread.sleepForTimeInterval(5.0) //your task here instead of this line

    dispatch_async(dispatch_get_main_queue(), {
      self.spinner.stopAnimating()
    })
  }
}

This starts the spinner,then dispatches to a background thread, performs a task there (I'm assuming the task you are performing is one that can be performed on a background thread - i.e it doesn't involve UI stuff). Once the task is complete, the method dispatches back to the main UI thread, and stops the spinner.

Sign up to request clarification or add additional context in comments.

1 Comment

Awesome, that works! My task is actually doing some UI stuff at the end, but I found I can move this also into the main queue dispatch where I stop the spinner. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.