UIAlertView Loading indicator doesn't work in a secondary thread - objective-c

I have following code for the UIAlertView Loading indicator which is not working and giving me
- (void) launchActivity
{
//some logic...
[NSThread detachNewThreadSelector:#selector(updateFilterProgress) toTarget:self withObject:nil];
}
- (void) updateFilterProgress {
if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN))
{
UIAlertView *myAlert = [[[UIAlertView alloc] initWithTitle:#"No Internet Connectivity" message:#"This app require an internet connection via WiFi or cellular network to work." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil] autorelease];
[myAlert show];
}
else{
UIAlertView *alertMe = [[[UIAlertView alloc] initWithTitle:#"Loading..." message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles: nil] autorelease] ;
//tried this way by placing below line....no result
[alertMe performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
//[alertMe show];
//some logic...
}
Updated:
On main thread I am calling web-service and loading data. hence I have given another thread for Loading UIAlertView and it was working with iOS 4,5. but its crashing in iOS 6. If I am placing AlerView on main thread then while loading nothing shows but after getting data loaded AlertView shows Loading Indicator for few seconds. Any suggestion...

You are showing the alert from the detached thread while you must do it from the main thread, either use GCD or performSelectorOnMainThread.
On the main thread you usually want to perform only the UI update, all the complex calculations and data loading are to be executed in the detached threads. If you try to load the data in the main thread, the UI will no be responding during the loading. So that is a good practice to load the data in the detached thread, on the main thread you show the alert as you need on the loading start and dismiss it on the loading (and parsing) finished, calling the content UI update as well:

It's a bad practise.
Apple docs say that you need to handle the UI elements on the main thread.
I think the issue is with this line:
[NSThread detachNewThreadSelector:#selector(updateFilterProgress) toTarget:self withObject:nil];
You won't handle the UI element on other threads rather than on main thread.
Use:
[self updateFilterProgress];
Or use like:
[yourAlert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
Also I checked with your code. There is one error popping up:
Error is: No visible #interface for 'UIAlertView' declares the selector 'performSelectorOnCurrentThread:withObject:waitUntilDone:'
The performSelectorOnMainThread is working perfectly for me.

Try this
- (void) launchActivity
{
//some logic...
[NSThread detachNewThreadSelector:#selector(updateFilterProgress) toTarget:self withObject:nil];
}
- (void) updateFilterProgress {
if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN))
{
[self performSelectorOnMainThread: #selector(showAlertForNoNetConnect)];
}
else{
[self performSelectorOnMainThread: #selector(showAlertForLoading)];
//some logic...
}
- (void) showAlertForNoNetConnect
{
UIAlertView *myAlert = [[[UIAlertView alloc] initWithTitle:#"No Internet Connectivity" message:#"This app require an internet connection via WiFi or cellular network to work." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil] autorelease];
[myAlert show];
}
- (void) showAlertForLoading
{
UIAlertView *alertMe = [[[UIAlertView alloc] initWithTitle:#"Loading..." message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles: nil] autorelease] ;
[alertMe show];
}
You have to call all the UIKit elements in the main thread. That's what the problem is.
Hope this helps. Happy Coding. :)

Related

UIAlertView makes the program crash

I've got a crash:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue performTask:] may only be called from the main thread.'
And I could not find a solution for 2 days.
And here is the code:
[alert dismissWithClickedButtonIndex:0 animated:YES];
UIAlertView *noTicketAlert = [[UIAlertView alloc] initWithTitle:#"Aradığınız kriterlere uygun bilet bulunamadı!" message:nil delegate:self cancelButtonTitle:#"Tamam" otherButtonTitles: nil];
[noTicketAlert show];
I triggered this error by attempting to display an alert from a background thread. Fixed like this:
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:...
[alertView show];
});
I got this error when presenting a UIAlertView normally (no funny button override stuff). It turned out that I was presenting it twice in quick succession. The fix in my case was to remove the erroneous duplicate call.
If you do need to present two alert views at close to the same time, and you get this error, then a fix that works (and addresses the error message itself) is to run the code on the main thread:
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
// Your code that presents the alert view(s)
}];
Yes, I've found the solution and I share that with you guys.
I tried to override the dismissWithClickedButtonIndex function, and sent unique buttonIndexes
like 9999 for each of my alerts.
That is,
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
[self viewWillDisappear:YES];
if(buttonIndex == 9999) {
noTicketAlert = [[UIAlertView alloc] initWithTitle:#"Aradığınız kriterlere uygun bilet bulunamadı!" message:nil delegate:self cancelButtonTitle:#"Tamam" otherButtonTitles: nil];
[noTicketAlert show];
}
}
and if I want to display the noticketAlert, I call this method like :
[alert dismissWithClickedButtonIndex:9999 animated:YES];
If you have a custom button make sure you implement the delegate method:
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
return YES;
}
if this selector is not found then the program with crash..
For those looking for the Swift 2 answer to this issue, I ran into a similar problem and solved it with #Dave Batton's solution
dispatch_async(dispatch_get_main_queue(), {
self.performSegueWithIdentifier("loginSegue", sender: self)
})

UIAlertView button results in a child NSThread

I would like a user to get a prompt screen, it would have yes and no options.
The problem is the UIAlertView cannot be called from child thread, if I call it from child thread I am getting a runtime error(EXC_BAD_ACCESS). I am using NSThread on IOS6.1
This is the code that i am using
-(void) construct
{
NSThread *initThread =[[NSThread alloc]initWithTarget:self selector:#selector(error) object:nil];
[initThread start];
}
- (void) error
{
//make sure it runs on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Save"
message:#"Enter File Name"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
[alertView show];
});
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSLog(#"Alert View dismissed with button at index %d",buttonIndex);
switch (alertView.alertViewStyle)
{
case UIAlertViewStylePlainTextInput:
{
UITextField *textField = [alertView textFieldAtIndex:0];
NSLog(#"Plain text input: %#",textField.text);
} break;
case UIAlertViewStyleSecureTextInput:
{
UITextField *textField = [alertView textFieldAtIndex:0];
NSLog(#"Secure text input: %#",textField.text);
} break;
case UIAlertViewStyleLoginAndPasswordInput:
{
UITextField *loginField = [alertView textFieldAtIndex:0];
NSLog(#"Login input: %#",loginField.text);
UITextField *passwordField = [alertView textFieldAtIndex:1];
NSLog(#"Password input: %#",passwordField.text);
}break;
default: break;
}
}
This is the error that I am getting:
[NSURLCacheInternal alertView:didDismissWithButtonIndex:]: unrecognized selector sent to instance 0x8653630
2013-07-26 16:12:35.738 iOSTrack[7455:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURLCacheInternal alertView:didDismissWithButtonIndex:]: unrecognized selector sent to instance 0x8653630'
*** First throw call stack:
(0x1e7a012 0x1796e7e 0x1f054bd 0x1e69bbc 0x1e6994e 0x7c0e13 0x408d66 0x408f04 0x20e7d8 0x266b014 0x265b7d5 0x1e20af5 0x1e1ff44 0x1e1fe1b 0x1dd47e3 0x1dd4668 0x3caffc 0x21cd 0x20f5)
libc++abi.dylib: terminate called throwing an exception
Most likely what is happening is that your UIAlertView is a local variable and it's getting destroyed before the delegate has a chance to run. You need to keep a reference to it around long enough such that your delegate has a chance to run and do it's work. Then you are in the clear. This concept applies to both ARC and manual memory managed based code.
See this related question: UIAlertViewDelegate class "self" instance gets dealloc'd before button gets pressed
The code I tried actually worked fine for me
The only difference is
[alertView show] => [alertView show]; you miss ;,a typo in question i guess
running the code in seperate thread
dispatch_queue_t myQueue = dispatch_queue_create("My Queue",NULL);
dispatch_async(myQueue, ^{
// Perform long running process
[self error];
});
- (void) error {
//make sure it runs on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Save"
message:#"Enter File Name"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
[alertView show];
});
}

UIAlertView wait_fences: failed to receive reply: 10004003

I get this error when I want to alert user if there is no internet connection
Please help me, Here is my code:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
__block UIAlertView *alert = nil;
//---------- Check Connection -------
// allocate a reachability object
Reachability* reach = [Reachability reachabilityWithHostname:#"www.google.com"];
// set the blocks
reach.unreachableBlock = ^(Reachability*reach) // not connected
{
//NSLog(#"UNREACHABLE!");
alert =
[[UIAlertView alloc]
initWithTitle: #"No Network Connection!"
message:#"Sorry, we can't currently connect you to the app. Please check your internet connection."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
//[alert release];
};
reach.reachableBlock = ^(Reachability*reach)
{
//NSLog(#"REACHABLE!");
};
// start the notifier which will cause the reachability object to retain itself!
[reach startNotifier];
}
The error is "wait_fences: failed to receive reply: 10004003"
Any Suggestions?
I got similar issue before. Because I was trying to display the alertview in a block.
I added the folowing line to my block instead of [alert show]; and everything worked fine.
[alertview performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:false];
Try to update your UI from Main Thread only, else it'll cause issues or show unpredictable results.

Cannot get UIAlert to work

Does somebody see something wrong with this? I have an UIAltertView but get an EXC_BAD_ACCESS when I click any of the two buttons:
UIAlertView *alert = [[UIAlertView alloc] init];
[alert setTitle:#"First Sync"];
[alert setMessage:#"The App is going to do its first synchronisation. This might take a few moment..."];
[alert setDelegate:self];
[alert addButtonWithTitle:#"OK"];
[alert addButtonWithTitle:#"Cancel"];
[alert show];
[alert release];
and to catch the response:
#pragma mark UIAlertView
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != 0)
{
NSLog(#"TEST1");
return;
}
NSLog(#"TEST2");
}
It must be something simple...
You'll have to use the designated initializer:
initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:
As hinted above, the problem was that the UIAlert was generated in a thread. By using an NSCondition and firing the Alert into a background thread I got the worker thread to wait while the background thread waits for a response from the user. Once the response comes it signals the worker thread to continue (as the required data is stored in the database at that point).

Trying to Integrate Mail Into my app, getting 2 warnings

I'm trying to integrate sending mail into my app, but I end up with 2 warnings. I am using Obj-C, the Cocos2d Framework. This is my code.
-(void) mailTapped: (id) sender {
MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
composer.mailComposeDelegate = self;
if ([MFMailComposeViewController canSendMail]) {
[composer setToRecipients:[NSArray arrayWithObjects:#"", nil]];
[composer setSubject:#"Check Out This Awesome App!"];
[composer setMessageBody:#"I found this great game on the App Store! It's called Mole Attack. It's a side scroller with an epic story. You can check out some screenshots of the gameplay and download it here. Download link - " isHTML:NO]; //Include link and pics
[self presentModalViewController:composer animated:YES]; // <--- warning - GameOver (name of class) may not respond to '-presentModalViewController:animated:'
}
}
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[self dismissModalViewControllerAnimated:YES]; // <--- warning - GameOver may not respond to '-dismissModalViewControllerAnimated:YES'
if (result == MFMailComposeResultFailed) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Failed" message:#"The email was not sent. You must be in wifi or 3G range. Try again later." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
}
Thanks in advance!
Are you sure your GameOver class is inheriting from UIViewController? That's the class that defines the two methods that you're getting warnings about.