Anton
Anton

Reputation: 339

swift: activity indicator after alert controller

If I create activity indicator programmatically in alertAction handler - it appears only after the code has finished and if there's no activityIndicator.stopAnimating(). Why? I want activity indicator to be spinning while processing time consuming function.

let alertController = UIAlertController(title: "Add", message: "", preferredStyle: .alert)

alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { _ in

let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
activityIndicator.color = .black
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
activityIndicator.startAnimating()
self.view.addSubview(activityIndicator)

timeConsumingFunc()

activityIndicator.stopAnimating()
}))

present(alertController, animated: true)

Upvotes: 2

Views: 677

Answers (3)

sundance
sundance

Reputation: 3050

You should run your time consuming task on a background queue and switch back to the main queue to update the UI:

DispatchQueue.global().async {
    timeConsumingFunc()
    DispatchQueue.main.async {
        activityIndicator.stopAnimating()
    }
}

You can also simplify and improve the activity indicator by using NVActivityIndicatorView:

let activityData = ActivityData()
NVActivityIndicatorPresenter.sharedInstance.startAnimating(activityData)
NVActivityIndicatorPresenter.sharedInstance.setMessage("Doing stuff...")
DispatchQueue.global().async {
    timeConsumingFunc()
    DispatchQueue.main.async {
        NVActivityIndicatorPresenter.sharedInstance.stopAnimating()
    }
}

Upvotes: 1

Pratyush Pratik Sinha
Pratyush Pratik Sinha

Reputation: 714

The change on UI happens only on main thread when their is a block. According to your scenario, you have to run this piece of code on main thread asynchronously.

DispatchQueue.main.async { [weak self] in //[weak self] is used for precaution from memory leak
    self?.timeConsumingFunc()
    self?.activityIndicator.stopAnimating()
}

Upvotes: 1

Sweeper
Sweeper

Reputation: 275045

The UI won't respond immediately after you do this:

self.view.addSubview(activityIndicator)

It will not update the UI until the next frame. During the time between this frame and the next frame, you already started to do the time-consuming function and starts it synchronously, so your UI freezes. The next frame is drawn when that finishes executing.

You need to do the work asynchronously:

DispatchQueue.main.async {
    [weak self] in 
    self?.timeConsumingFunc()
    self?.activityIndicator.stopAnimating()
}

or on a different dispatch queue altogether.

Upvotes: 2

Related Questions