Cannot get UIAlert to work - cocoa-touch

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).

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 Loading indicator doesn't work in a secondary thread

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. :)

how to hide uialertview when its enter its delegate method?

hi guys I have a method called manageui which display a waiting view for a while and when the times out it's display UIAlertView which display a message for try again
My problem is that i can't hide the UIAlertView before calling manageui called
here is my code :
-(void)mangeui
{
double Currenttime=0;
double ptime=Currenttime+5000;
NSLog(#"fire /n");
do
{
//add condition for found session
if (Currenttime<ptime)
{
NSLog(#"inside if");
[spinner setHidden:NO];
[alert setHidden:YES];
}
else
{
alert = [[UIAlertView alloc] initWithTitle:#"Oops:("
message:#"No device found \n Make sure bluetooth is activated and the devices are within range."
delegate:self
cancelButtonTitle:#"Tap to retry"
otherButtonTitles:nil];
[spinner setHidden:YES];
[alert show];
}
Currenttime+=1;
} while (Currenttime < ptime+1 &&[_matchmakingClient availableServerCount]==0);
}
the delegate for alertview is :
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[alertView dismissWithClickedButtonIndex:1 animated:true];
[spinner setHidden:NO];
alertView.hidden=YES;
[self mangeui];
}
Try this:
[alertView dismissWithClickedButtonIndex:0 animated:YES];
Well I think you didn't understand the concept of delegates
here in docs it says alertView:clickedButtonAtIndex:
The receiver is automatically dismissed after this method is invoked.
yeah there is no need to declare separately to dismiss the alert view.The method is called whenever a button in alertview is pressed and the alertview disappears

popViewController doesn't work with UIAlertView

I am having problem with AlertView. I am trying to use the UIAlertView and after click ok it will return back to the previous screen but it do not seems to work any advice ?
if (xGPSCoordinate==0 && yGPSCoordinate == 0) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title"
message:#"Failed to load the to get your current location"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
[alert show];
[alert release];
return;
[self.navigationController popViewControllerAnimated:YES];
}
or
if (xGPSCoordinate==0 && yGPSCoordinate == 0) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"iPoly"
message:#"Failed to load the to get your current location"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
[alert show];
[alert release];
[self.navigationController popViewControllerAnimated:YES];
return;
}
both doesn't work
For this purpose you've to use UIAlertView's delegate method.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;
First use this in your #interface <UIAlertViewDelegate>
Then set the delegate, self.yourAlertView.delegate=self;
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex==0)//first button which should be the OK button
{
[self.navigationController popViewControllerAnimated:YES];
}
}
use the delegate method of UIAlertView, see the answer given by iNoob. It does not make a sense if you write anything after the "return;" statement as the code below "return;" statement will never get executed.
refer apple developer link for more details on UIAlertView delegate http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIAlertViewDelegate_Protocol/UIAlertViewDelegate/UIAlertViewDelegate.html
or a simple tutorial on alert view
http://mobile.tutsplus.com/tutorials/iphone/uialertview/
You just need to implement UIAlerView Delegate Methods.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{}
write your code for Pop to previous Controller here.You can the clicked button index and on the basis of that you can use.Don't for Conform UIAlertViewDelegate to Interface.

UIAlertView without any buttons

I wanted to know whether the following code is okay or not. I am trying to dismiss the alertView automatically after 2 seconds (and without any buttons in the alertView) from the "timedAlert" method.
//this is in another method
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"Login successful." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
[alert show];
[alert release];
[self timedAlert];
}
-(void)timedAlert
{
[self performSelector:#selector(dismissAlert:) withObject:alert afterDelay:2];
}
-(void)dismissAlert:(UIAlertView *) alertView
{
[alertView dismissWithClickedButtonIndex:nil animated:YES];
}
If the cancelButton of the alertView is set to "nil", how will the "[alertView dismissWithClickedButtonIndex:0 animated:YES];" thing work??? I tried making the cancelButton "nil" and it worked, but cant figure out how....
P.S: I call the timedAlert method from another
Any help is appreciated! Thank you!
First let me say it would be better if you handle this with a custom view, but with that said the problem looks to be with
[alert release];
You are releasing the object before you are done with it (I am surprise it does not crash).
Do something like this
// other code
alert = [[UIAlertView alloc] initWithTitle:nil message:#"Login successful." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
[alert show];
[self performSelector:#selector(dismissAlert:) withObject:alert afterDelay:3.0f];
}
-(void)dismissAlert:(UIAlertView *) alertView
{
[alertView dismissWithClickedButtonIndex:nil animated:YES];
[alertView release];
}
Your code should work, and you should have no problems. I have done this in one of my previous apps. The button is not displayed because the title is nil but I think the instance of the button still exists. Put a breakpoint before closing your alert and take a look at the alert variable, and check to see if there is a buttons array or something, that should tell you how that works.