if I show an Alert and then call a method of an Activity Indicator, the alert disappears like the user has pressed OK.
Declaration of alert:
UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
Declaration of Activity Indicator:
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
indicator.hidesWhenStopped = YES;
[indicator stopAnimating];
Method call which causes this problem:
[indicator stopAnimating];
What can I do?
Edit: I noticed that my app isn't working correct, if NSXML Parser is getting a wrong URL. At the moment I cannot say if the activity indicator is causing a error.
you could have the ActivityIndicator embedded in your alertview, looks neat and tidy:
http://kwigbo.com/post/394670170/iphone-sdk-uialertview-with-activity-indicator
Edit: Re-read your question, above solution might not be suitable for your needs.
Let me ask, what exactly are you trying to do with those two views?
Related
I call alert with progress indicator view while calling web services.i am having an alert view set up like this:
[self.activityIndicatorView setHidden:NO];
self.alertView = [[UIAlertView alloc] initWithTitle:#"Sending Login Request.."
message:#"\n"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
self.activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.activityIndicatorView.center = CGPointMake(139.5, 75.5); // .5 so it doesn't blur
[self.alertView addSubview:self.activityIndicatorView];
[self.activityIndicatorView startAnimating];
[self.alertView show];
Later if login fails I want to put "OK" button on alert view, withot dismissing self.alertView, and again showing new instance of self.alertView.Some thing like this:
if (isThereErrorFromJsonResp) {
[self.activityIndicatorView stopAnimating];
[self.activityIndicatorView removeFromSuperview];
self.activityIndicatorView = nil;
[self.alertView setTitle:isThereErrorFromJsonResp];
//here i want to show ok button how?
return;
}
So how should i put OK button?
Any Suggestion?
Remove the alert on getting the response and display an new instance of alert like this
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
self.alertView = [[UIAlertView alloc] initWithTitle:isThereErrorFromJsonResp
message:#"\n"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[self.alertview show];
SOLUTION
Ok tried out and got it
Use
[alertView dismissWithClickedButtonIndex:0 animated:YES];
[alertView addButtonWithTitle:#"Ok"];
[alertView show];
This will add the button to the alertview
Look at using ATMHud instead - this is a heads-up-display that you can modify while its showing, and can show, start, stop, spinners, add messages etc. When I used it I had a message say "Tap to Cancel", then when the login succeeded, showed a "Success!" for a second or so, then made it disappear. This looks HUD looks very professional in the way it animates, and you have a lot of control over it too.
Try this code:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"" message:#"Logout in offline mode may cause of data lose. Do you still want to logout?" delegate:self cancelButtonTitle:#"NO" otherButtonTitles:#"YES",nil];
alert.tag=11;
[alert show];
[self performSelector:#selector(go:) withObject:alert afterDelay:1.0];
-(void)go:(UIAlertView*)alert
{
UIButton *b = (UIButton*)[alert viewWithTag:1];
b.titleLabel.text = #"test";
}
you will have to add "OK" button initially. And set its property as Hidden = TRUE. and in go method set it property Hidden = FALSE
I am bringing up an UIAlertView that works fine in portrait layout, but when in landscape mode - the message doesn't appear.
It is a standard UIAlertView, with three buttons.
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"cancel" otherButtonTitles:#"one", #"two", nil];
I have tried moving the buttons down (according to the height of the message label) and resizing the alert according to the relocated buttons, but the message still doesn't appear, despite there being plenty of room for display.
Setting the UILabel background to some color for debugging shows that it just isn't displayed..
EDIT:
The UILabel is there - It's just not being displayed.
In the willPresentAlertView method, I can see the UILabel in the NSAlertView's subviews.
It appears to be a bug with the layout code for UIAlertView. After fiddling a bit in the debugger I managed to get this workaround:
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"cancel" otherButtonTitles:#"one", #"two", nil];
[alert show];
// for some reason we have alpha 0 for 3 or 4 buttons
[[[alert subviews] objectAtIndex:2] setAlpha:1];
// also, for 3 buttons the height goes to 10 -> proof of concept 'fix'
[[[alert subviews] objectAtIndex:2] setFrame:CGRectMake(12, 45, 260, 24)];
[alert release];
This is just a proof of concept. A real workaroung should iterate ober the subviews and fix only labels that have either height to small or alpha==0
Probably you missed:
[alert show];
You can directly use uialertview and create object of it. Then pass title and message and button and also other button.....And call click button method.
//Example
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Title" message:#"The message."
delegate:self cancelButtonTitle:#"button 1" otherButtonTitles:#"button", nil];
[alert show];
[alert relaese];
//Then use this method
-(void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
// the user clicked one of the ok/cancel buttons
if(buttonIndex==0)
{
NSLog(#"Ok");
}
else
{
NSLog(#"cancel");
}
}
I am implementing a simple alert view with activity indicator to show to the user while the app is performing the restore of the database. Everything is fine except that I can't see the alert view, unless I comment out the automatic dismiss line (last one here).
Ok, the restore of the database is quite quick, but still I would expect to see it even if for an instant, no? I can see the screen get's a little darker during animation but that's all. I also tried putting a for loop to extend the time, the time extends but still no alert view.
There is nothing wrong in the way the alert view is called, since if I comment the dismiss, I can see it...only forever. Anyone has an idea here?
Before anyone says it, I tried changing the delegate of the alertView to self as posted here, but it didn't help.
// First we prepare the activity indicator view to show progress indicator
UIActivityIndicatorView * activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[activityView setFrame:CGRectMake(121.0f, 50.0f, 37.0f, 37.0f)];
[activityView startAnimating];
// Then we put it in an alert view
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Loading" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
[alertView addSubview:activityView];
[alertView show];
// Finally we operate the restore
[[SQLManager sharedSQL] restoreDatabase:[restoreDatabaseURL path]];
// And we can dismiss the alert view with the progress indicator
[alertView dismissWithClickedButtonIndex:0 animated:NO];
Im not sure why this happens, but I encounter it occasionally as well. One way I have gotten something like this to work is by using performSelector:withObject:afterDelay: on the next call, like this:
// First we prepare the activity indicator view to show progress indicator
UIActivityIndicatorView * activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[activityView setFrame:CGRectMake(121.0f, 50.0f, 37.0f, 37.0f)];
[activityView startAnimating];
// Then we put it in an alert view
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Loading" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
[alertView addSubview:activityView];
[alertView show];
// Finally we operate the restore
// [[SQLManager sharedSQL] restoreDatabase:[restoreDatabaseURL path]];
[[SQLManager sharedSQL] performSelector:#selector(restoreDatabase:) withObject:[restoreDatabaseURL path] afterDelay:0.25];
// And we can dismiss the alert view with the progress indicator
[alertView dismissWithClickedButtonIndex:0 animated:NO];
performSelector Documentation
Sounds like it's dismissing itself almost instantaneously. If you add a for loop, it will likely freeze all other computations which means your activity view won't show up until the loop breaks.
You could try using a NSTimer to call another function to determine if the restore is complete or not;
// Setup our the timer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(checkRestore)
userInfo:nil
repeats:YES];
// Timer function checking for completion
-(void)checkRestore {
if (restore is complete) {
[alertView dismissWithClickedButtonIndex:0 animated:NO];
}
}
i have the following code.
UIActivityIndicator *activity = [[UIActivityIndicator alloc] initWithActivityIndicatorStyle:
UIActivityIndicatorStyleWhite];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Processing" delegate:self otherButtonTitles:nil];
[alert addSubview:activity];
[activity startAnimating];
[alert show];
WebServiceController *web = [[WebServiceController alloc]init];
NSDictionary *dict = [web getDetails];
The problem is that the alert is not getting displayed. The WebServiceController is an XML parser which gets details from a specified URL and returns them. The alert should be shown while the service is called as it takes time to get the details. But it displays the alert only after the service call is over. Why is that?
because [alert show] will require animation, since the service controller call is taking place on the main thread, the main thread is busy executing the service call, blocking the alert view animation to execute.
You need to perform the ServiceCall on backend thread, see NSOperation or PerformSelectorOnBackgroundThread, make sure you pass in delegate of the ViewController that has the AlertView to the backend thread, callback the delegate as soon as the service call is completed. Make sure you perform the call for the callback on the mainthread using performSelectorOnMainThread. All UI related calls should be executed on the main thread.
Adding to the above post, you have to write the alert like this:
UIActivityIndicator *activity = [[UIActivityIndicator alloc] initWithActivityIndicatorStyle:
UIActivityIndicatorStyleWhite];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Processing" delegate:self otherButtonTitles:nil];
[alert addSubview:activity];
[activity startAnimating];
[alert show];
[self performSelectorInBackground:#selector(doTheWork) object:nil];
You need to declare a function (doTheWork) which will take care of the web service call as follows:
-(void)doTheWork {
WebServiceController *web = [[WebServiceController alloc]init];
NSDictionary *dict = [web getDetails];
[alert dismissWithClickedButtonIndex:0 animated:YES]; //dismissing the alert
}
I load data from a webservice in a background thread. Is it safe to show an UIAlertView in the background thread when anything goes wrong or should I show the alert view in the mainthread ?
thanks for the advice
Frank
Never do anything with the GUI except from the main thread. It can cause very weird issues and or crashes you don't want to deal with. Usually the backtraces are also very unhelpful so try to avoid such issues by default.
Therefore use this:
[self performSelectorOnMainThread:#selector(showAlert:) withObject:alertString waitUntilDone:NO];
If you are using grand Central dispatch you could do something like:
dispatch_async(dispatch_get_main_queue(), ^{ /* show alert view */ });
Update:
Swift (3.0+):
DispatchQueue.main.async { // code }
It is sometimes helpful to do this with Notifications you receive as well, I have had instances where they were fired from a different thread.
Update 2:
It looks like apple has added some new tools coming in iOS11/Xcode9 to help debug issues where stuff is called on the incorrect thread.
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
});
this code works for me
You could try showing the alert on the main thread by:
UIAlertView *alert = [
[[UIAlertView alloc] initWithTitle:#"the title"
message:#"the message"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles: nil] autorelease];
[alert performSelector:#selector(show)
onThread:[NSThread mainThread]
withObject:nil
waitUntilDone:NO];
[alert release];