Say you’ve got a long running process and you want to popup a spinner while your process is working. Here’s how you do it.
ViewController.h
#import <UIKit/UIKit.h> @interface rcsViewController : UIViewController @property (weak, nonatomic) IBOutlet UILabel *myLabel; @property (weak, nonatomic) IBOutlet UIButton *myButton; @end
ViewController.m
#import "rcsViewController.h" @implementation rcsViewController @synthesize myLabel; @synthesize myButton; - (IBAction)process:(id)sender { // replace right bar button 'refresh' with spinner UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; spinner.center = CGPointMake(160, 240); spinner.hidesWhenStopped = YES; [self.view addSubview:spinner]; [spinner startAnimating]; // how we stop refresh from freezing the main UI thread dispatch_queue_t downloadQueue = dispatch_queue_create("downloader", NULL); dispatch_async(downloadQueue, ^{ // do our long running process here [NSThread sleepForTimeInterval:10]; // do any UI stuff on the main UI thread dispatch_async(dispatch_get_main_queue(), ^{ self.myLabel.text = @"After!"; [spinner stopAnimating]; }); }); dispatch_release(downloadQueue); } - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewDidUnload { [self setMyLabel:nil]; [self setMyButton:nil]; [super viewDidUnload]; } @end
The magic happens when the users presses the button. Here we create our spinner, add it to our subview, and start it up.
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; spinner.center = CGPointMake(160, 240); spinner.hidesWhenStopped = YES; [self.view addSubview:spinner]; [spinner startAnimating];
Once it’s going we create a separate thread to do our processing in, along with a call to the main UI thread when it’s done (which changes the label and stops the spinner).
dispatch_queue_t downloadQueue = dispatch_queue_create("downloader", NULL); dispatch_async(downloadQueue, ^{ // do our long running process here [NSThread sleepForTimeInterval:10]; // do any UI stuff on the main UI thread dispatch_async(dispatch_get_main_queue(), ^{ self.myLabel.text = @"After!"; [spinner stopAnimating]; }); });
That’s it!
Oct 15, 2012 @ 00:25:46
Holy Amazing. I have never seen any tutorial for this on the internet and its great! Totally fixed my problem, would never have thought of this!
Nov 21, 2012 @ 00:30:58
Couldn’t get it to work in my case as I’m trying to get the spinner to appear at the start of performsegue after which I save some data to the db and then I want the spinner to stop before segue-ing to the next screen. Any comments on that?
I tried two things
1. Put the spinner startAnimating in a seperate thread before the db update
2. Put the spinner startAnimating in the main queue before the db update like you have done for the spinner stopAnimating.
Neither way seemed to work as expected, which is to show the spinner right after user hits the “segue” button.
Nevertheless, great tutorial! Hard to find such sweet stuff on the internet.
Mar 01, 2013 @ 08:52:40
Thank you very much. Helps me a lot 🙂
Jul 10, 2013 @ 05:24:10
Thanks, it is very nice .
Sep 30, 2013 @ 22:12:38
I have been looking for a simple and elegant solution for this exact thing for over a year. You Sir deserve a medal or something! This is great!
Thank you!
Nov 05, 2013 @ 18:00:24
Great tutorial! Thanks man! I’ve been looking for something like this all day long!
Mar 02, 2014 @ 15:03:18
Thanks Man! Simple and to the Point 🙂
Mar 28, 2015 @ 13:06:53
Hey mate – Freak-in’ Awe-soom.
I was trying to add a label, to tell my user, that I was saving all his data. But, it kept doing all the array updates, and then .. finally added the ‘Loading’ label, AFTER the saving was done. (drive me crazy – don’t understand).
I figured it was something to do with how the stack manages tasks.
And your bit of code, made my world rosy.
Will you be my tutor 😉
Thanks,
Andrew
Mar 28, 2015 @ 13:16:34
ps. I had to remove the last line…
dispatch_release(downloadQueue); //_____ not suitable for ARC.
Aug 18, 2015 @ 07:17:01
Go to: Targets → Your App → Build Phases → Compile Sources
Select All Files That Use ARC → Hit Enter
Add “-fno-objc-arc” (Wihout the quotes) → Hit enter again.
Build and see the ARC errors disappear 🙂
Aug 18, 2015 @ 07:40:45
Thanks Chetan – love these tips.
Oct 07, 2015 @ 10:25:32
useful… thanks man…
Dec 18, 2015 @ 19:40:37
spinner.center = self.view.center; // Do not hardcode position