If you want the app to be responsive while doing some heavy task, you will need to execute it on a background thread.
This is roughly what's going on here: The main thread of your app executes in a run loop. At the beginning of each loop iteration, the iOS checks for any events (such as user interaction, views changing due to animation, timers being fired, etc.) then queues a bunch of methods to be executed. iOS then goes and executes each of those methods and then, once everything is complete, it updates the display. Then the next run loop iteration begins. Updating the display is costly, so iOS can't do it after every line of code is executed.
So with your code, when you tell the activityIndicator to startAnimating, it tells iOS that at the end of every run loop iteration that the activity indicator image needs to be updated to the next image in the animation sequence. Then, before iOS reaches the end of the current run loop iteration, you are calling stopAnimating which tells iOS that it doesn't need to update the images anymore. So basically you're telling it to stop before it has even started.
You can use Grand Central Dispatch to easily run code on a different thread. It's important to note however that any updates to the UI must be done on the main thread.
func heavyWork() {
self.activityIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// Do heavy work here
dispatch_async(dispatch_get_main_queue()) {
// UI updates must be on main thread
self.activityIndicator.stopAnimating()
}
}
}
Also note when programming asynchronously, such as in the above example, you cannot return a value from the asynchronous section in the method that invoked it. E.g. in the example above, you cannot return a result of the heavy work from the heavyWork() method. This is because the function schedules the async code to run on a different thread then returns immediately so it can continue with the current run loop iteration.
SWIFT 4
func heavyWork() {
activityIndicator.startAnimating()
DispatchQueue.global(qos: .default).async {
// Do heavy work here
DispatchQueue.main.async { [weak self] in
// UI updates must be on main thread
self?.activityIndicator.stopAnimating()
}
}
}
heavy loop code
running on a background thread? The heavy loop code will block the UI from displaying the activity indicator. Further if you are callingheavyWork
on a background thread theUI
shouldn't update as it is not on the main thread. – Manatee