UIActivityIndicatorView not showing up when invoke

2019-03-02 15:05发布

问题:

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?

回答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.