In a method that can take up to several seconds i have:
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(135,140,50,50)];
spinner.color = [UIColor blueColor];
[spinner startAnimating];
[_mapViewController.view addSubview:spinner];
// lots of code
[spinner removeFromSuperview];
The spinner doesn't show up. Probably since the screen doesn't get update at that time.
How can i get around this problem?
Use GCD:
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(135,140,50,50)];
spinner.color = [UIColor blueColor];
[spinner startAnimating];
[_mapViewController.view addSubview:spinner];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// lots of code run in the background
dispatch_async(dispatch_get_main_queue(), ^{
// stop and remove the spinner on the main thread when done
[spinner removeFromSuperview];
});
});
Related
In my code, I initialize a UIActivityIndicator, and add it as a subview, but it never appears. What's going wrong?
-(void) update {
UIActivityIndicatorView *activityView=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityView.center=self.view.center;
[self.view addSubview:activityView];
[activityView startAnimating];
/** Stuff to access to server, this stuff works correctly.*/
[activityView stopAnimating];
}
As you are starting and stoping the activity as same runloop so it will not get change to update the UI.You are doing all server stuff on same synchronously than you are blocking the runLoop and do not giving time to activity indicator to start.You should start server stuff on next runLoop so activity indicator will get time to start.So use performSelector with delay 0.0 it will start the activity indicator and than perform your server stuff on immediate next runloop and than stop the activityInddicator
-(void) update {
UIActivityIndicatorView *activityView=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityView.center=self.view.center;
[self.view addSubview:activityView];
[activityView startAnimating];
//Use performSelector with 0.0 so activity indicator starts
[self performSelector:#selector(thisWillStartAtNextRunLoop) withObject:nil afterDelay:0.0];
}
-(void)thisWillStartAtNextRunLoop{
/** Stuff to access to server, this stuff works correctly.*/
[activityView stopAnimating];
}
Edit execute it on main thread as all UI updation must be on main thread
Try
-(void) update {
dispatch_async(dispatch_get_main_queue(), ^{
UIActivityIndicatorView *activityView=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityView.center=self.view.center;
[self.view addSubview:activityView];
[activityView startAnimating];
});
/** Stuff to access to server, this stuff works correctly.*/
}
I have a method to retrieve data from an external url, load it into an array from JSON format, and populate a UITableView. It works fine, but there is no indication to the user that something is happening while the data is downloaded.
- (void)viewDidLoad
{
[super viewDidLoad];
[self retrieveDataC];
}
Here is the code that I tried for viewDidLoad which adds a spinner animation while downloading. I'm attempting to put retrieveDataC on a background thread and when it completes, I would like the view to continue executing as though I didn't implement the multi-threading in the example above.
- (void)viewDidLoad
{
[super viewDidLoad];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.center = CGPointMake(160, 240);
[self.view addSubview:spinner];
[spinner startAnimating];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self retrieveDataC];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
});
});
}
The loading spinner displays correctly for a brief moment, however after the process is done I'm left with a blank table as though I have not called [self retrieveDataC] to begin with. Any suggestions, advice? Am I setting up the background process correctly?
Thank you
EDIT:
Here's what ended up working -
- (void)viewDidLoad
{
[super viewDidLoad];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(160, 240);
[self.view addSubview:spinner];
[spinner startAnimating];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self retrieveDataC];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
[self.collectionView reloadData];
});
});
}
Do you call [self.tableView reloadData] after you received the data?
In my application, I need to show a UIActivityIndicator while waiting for response from web service. I am using the following code:
UIView *loadView = [[UIView alloc] initWithFrame:self.view.bounds];
loadView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
//UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] init];
//[second.loadingView addSubview:activityView];
//activityView.center = second.loadingView.center;
//[second.view addSubview:second.loadingView];
UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[loadView addSubview:activity];
activity.center = loadView.center;
[self.view addSubview:loadView];
[self.view bringSubviewToFront:loadView];
activity.hidesWhenStopped = YES;
[activity setHidden:NO];
[activity startAnimating];
// calling My web service
[self callRegisterWebService:self.userFname lastName:self.userLName email:self.userEmail];
[activity stopAnimating];
[loadView setHidden:YES];
However, the indicator does not show up..!! What am i doing wrong??
You are probably waiting for the http response on the main thread. Try to implement the registration with dispatch_async function like this:
[activity startAnimating];
// calling My web service
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self callRegisterWebService:self.userFname lastName:self.userLName email:self.userEmail];
[activity stopAnimating];
});
I have an app with a table view controller in which a user selects a US state, a web service is called and data is displayed for that state in the destination table view controller. Since the web service can take some time to complete I want an activity indicator. Since there will be no temporary data to display, I need this to be processed synchronously. So my task is pretty simple: start the activity indicator, call the web service, and after it completes, stop the activity indicator.
I am obviously doing something wrong and no activity indicator ever displays.
Here is the code from my destination table view controller's viewDidAppear method:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
[self.tableView reloadData];
[spinner stopAnimating];
}
Header:
#property (strong, nonatomic) UIActivityIndicatorView *spinner;
GaugeList is the object which makes the web service call.
Can someone tell me how to get an activity indicator view to appear? Thanks!
You forgot to add spinner on table view. Your code should look as follows:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spiner.center = //set some center
[self.tableView addSubview: spinner];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
[self.tableView reloadData];
[spinner stopAnimating];
}
Also you send requests to a web service in main thread. This is bad practice. I would suggest something like following:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spiner.center = //set some center
[self.tableView addSubview: spinner];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[spinner stopAnimating];
});
});
}
At first you should add activity indicator to some view to show it. But you can not add it to UITableView, because UITableView is subclass of UIScrollView and you will see floating activity indicator. The best way in your case is to add activity indicator to navigation bar, etc. Or if you want to disable table view you should write something like this:
- (void)viewDidLoad {
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
UIView *dummyView = [[UIView alloc] init];
dummyView.frame = self.tableView.bounds;
dummyView.alpha = 0.5f;
dummyView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
dummyView.userInteractionEnabled = YES;
dummyView.backgroundColor = [UIColor blackColor];
[dummyView addSubview:activityIndicator];
activityIndicator.center = dummyView.center;
[self.tableView addSubview:dummyView];
}
Try using self.spinner instead of using spinner.
All
I am trying to run UIActivityIndicator for a 5 seconds on viewdidappear method .But how do i give a time limit for activity indicator(5 seconds) ?
This is the code for UIActivityIndicator
UIActivityIndicatorView *activityView=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityView.center=self.view.center;
[activityView startAnimating];
[self.view addSubview:activityView];
With one line and no additional dependencies & conditions:
[activityView performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:5.0];
Set activity view to hide automatically when stopped
activityView.hidesWhenStopped = YES;
And hide it after 5s like this:
[activityView performSelector:#selector(stopAnimating) withObject:nil afterDelay:5.0];
This will allow you to start animation again by just calling startAnimating if you need so in the future and keep pointer to the UIActivityIndicatorView
If you just need to show activity indicator once and will not use it anymore, Alexanders answer will suit best to your needs
Use NSTimer for 5 sec.
In the call back method of timer stop the animation
try this code,
-(void)viewDidAppear:(BOOL)animated
{
UIActivityIndicatorView *activityView=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityView.center=self.view.center;
[self.view addSubview:activityView];
[activityView startAnimating];
activityView.tag=1111;
[activityView release];
}
[activityView performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:5.0];
-(void)removeFromSuperview
{
UIActivityIndicatorView *activityView=(UIActivityIndicatorView*)[self.viewviewWithTag:1111];
[activityView stopAnimating];
[activityView removeFromSuperview];
}