Show UIAlertView in background thread - iphone

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];

Related

Why is app crashing when showing UIAlertView?

I've implemented the Reachability function in a method that handles all the server requests. I can see through NSLogs that the function works perfectly. However there is never a "pause" within the method which means I can't use the UIAlertView without crashing the program.
I might be going at this the completely wrong way, but I can't find anything else...
Does anybody have an idea of how to get a notification to show somehow?
Thanks in advance
CODE:
-(id) getJson:(NSString *)stringurl{
Reachability * reach = [Reachability reachabilityWithHostname:#"www.google.com"];
NSLog(#"reached %d", reach.isReachable);
if (reach.isReachable == NO) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Passwords don't match."
message:#"The passwords did not match. Please try again."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}else{
id x =[self getJsonFromHttp:stringurl];
return x;
}
return nil;
}
After moving the discussion to a chat, we discovered that your UIAlertView was being called from a background thread. Never do anything related to updating the UI (User-Interface) in a background thread. The UIAlertView updates the UI by adding a little pop-up dialog, so it should be done on the main thread. Fix by making these changes:
// (1) Create a new method in your .m/.h and move your UIAlertView code to it
-(void)showMyAlert{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Passwords don't match."
message:#"The passwords did not match. Please try again."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
// (2) In -(id)getJson replace your original UI-related code with a call to your new method
[self performSelectorOnMainThread:#selector(showMyAlert)
withObject:nil
waitUntilDone:YES];

warning : wait_fences: failed to receive reply: 10004003

I am getting this warning sometimes " wait_fences: failed to receive reply: 10004003 ", do not know why this is coming,
I do not have viewdidiappear method in my code, i have a UIAlert in my view, the code is
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Start" message:[NSString stringWithFormat:#"Hi %#,",[user objectAtIndex:0] ] delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
this is due to UI actions on a view controller on which you are not currently,i.e. the screen of which you are accessing UI, not visible currently.
if you read my answer in the comment you would understand, but what you need to do is add the above code in the -viewDidAppear method and make sure you add [super viewDidAppear:YES]; and if you want to keep it in your init method you'll have to add a delay like so
[self performSelector:#selector(next) withObject:nil afterDelay:0.5];

Showing alert while calling webservice

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
}

Why isn't UIAlertView Showing?

For some reason screen gets dark and freezes, alert is not shown... can someone please help?
Thanks in advance!
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Hello!"
message:#"Hello!" delegate:self
cancelButtonTitle:#"Done"
otherButtonTitles:nil];
[alert show];
[alert release];
}
You are probably calling show from a background thread, call it on the main thread like this:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Hello!"
message:#"Hello!" delegate:self
cancelButtonTitle:#"Done"
otherButtonTitles:nil];
[alert performSelectorOnMainThread:#selector(show)
withObject:nil
waitUntilDone:NO];
[alert release];
Delegate is correct, but maybe because your do a release at the end it may cause a problem.
Try with a nil delegate :-)
For example :
UIAlertView *alertView;
alertView = [ [ UIAlertView alloc ] init ];
[ alertView setMessage:#"Hello World" ];
[ alertView show ];
[ alertView release ];
If it works, then it was the delegate and you need to declare the variable as a class var. Or it maybe be elsewhere.
Is this alert maybe sitting in a big loop and you are not running on multiple threads? The screen darkening and nothing happening is something I equate with running a long process on the main thread (so the UI doesn't refresh and show the alert).
You get a dark screen without a popup, or slower popup if you show the UIAlertView from a background thread. Just out it back in the main thread and it will be fine. I just had this problem last week.

UIAlertViews disappear when calling UIActivityIndicatorView method

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?