I have 2 view controllers, ViewController 1(VC1) and 2(VC2). In VC2 I have a back and done button. On clicking back button it goes directly to VC1 and on done it makes an api call and when it gets a response it shows an alert view and clicking ok goes back to VC1. Now when I make a api call a loading bar shows up and disappears when I get response and shows the AlertView. But if during that fraction of second when the loading disappears and AlertView is going to be popped up if I click on back and the view changes to VC1, the alert appears on VC1 and results in a crash.
This is a rare case as no user will purposely try for it but I was wondering if that crash can be managed without disabling the back button. I think there can be other instance such cases like if we are making an asynchronous calls and if the user is allowed to use UI while waiting for response and if any error alert that was suppose to show on one ViewController shows up in another may result in crash since the delegate that alert is referring to is that of the previous view controller. So is there any way to handle this kind of crash efficiently?
//Alert View sample
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[[message objectAtIndex:1] capitalizedString] message:[message objectAtIndex:0] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] ;
[alert setTag:701];
[alert show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([alertView tag] == 701)
if (buttonIndex == 0)
{
[self.navigationController popViewControllerAnimated:YES];
}
}
The proper way to fix this problem is to use an instance variable to keep a reference to the alert view.
This instance variable should be set to nil in the alertView:didDismissWithButtonIndex: delegate method.
In the view controller's dealloc method, you call dismissWithClickedButtonIndex:animated: if the instance variable is still set.
Assume _alertView is the instance variable.
Create the alert:
_alertView = [[UIAlertView alloc] initWithTitle:[[message objectAtIndex:1] capitalizedString] message:[message objectAtIndex:0] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] ;
[_alertView setTag:701];
[_alertView show];
Update your existing alertView:clickedButtonAtIndex: method:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if ([alertView tag] == 701) {
_alertView.delegate = nil;
_alertView = nil;
if (buttonIndex == 0) {
[self.navigationController popViewControllerAnimated:YES];
}
}
}
Add:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
_alertView = nil;
}
Add:
- (void)dealloc {
if (_alertView) {
_alertView.delegate = nil;
[_alertView dismissWithClickedButtonIndex:_alertView.cancelButtonIndex animated:NO];
_alertView = nil;
}
}
Related
I have two different view controllers, one for a dashboard and one for registration. I do not want the user to be able to interact with anything on the dashboard until the user logs in through an alertview. So every time the user navigates back to the dashboard or presses cancel and they are not logged in, I want the login alert to popup.
This works perfectly in all cases, including when the user hits the back button on the navigation bar in the registration view, but does not work when the user clicks OK on the alert in the registration page.
the dashboard view contains this code:
#property(strong) UIAlertView * alert;
//...
-(void)viewWillAppear:(BOOL)animated
{
user_email = [[NSUserDefaults standardUserDefaults] stringForKey:#"email"];
if ( user_email==nil ){
[self auto_login];
} else //...
}
-(void)auto_login
{
alert = [[UIAlertView alloc] initWithTitle:#"Login" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Login",#"Forgot Password",#"Register",nil];
alert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
case 0:
{
self.debug.text = #"Cancel";
[self auto_login];
break;
}
//...
default:
{
self.debug.text = #"Register";
[self nav_register];
break;
}
}
}
-(void)nav_register
{
RegisterProfileController *rvc = [[RegisterProfileController alloc] init];
[self.navigationController pushViewController:rvc animated:YES];
}
The registration view controller contains this code:
-(void)catch_registration
{
NSString *response = [[NSString alloc] initWithData:self.httpdata encoding:NSASCIIStringEncoding];
if( [response isEqualToString:#"OK"] ){
UIAlertView *successAlert = [[UIAlertView alloc] initWithTitle:#"Success" message:#"..." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
successAlert.alertViewStyle = UIAlertViewStyleDefault;
[successAlert show];
}
else //...
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([alertView.title isEqualToString:#"Success"])
[self.navigationController popViewControllerAnimated:TRUE];
}
After debugging, I know that after clickedButtonAtIndex runs in the registration view controller, [alert show] runs in the dashboard view controller, and clickedButtonAtIndex does NOT run in the dashboard view controller, but no alert shows up.
Why isn't the alert showing or how can I debug this further?
If clickedButtonAtIndex "does NOT run" as you said, then the delegate might not be set correctly. In addition, you should likely move the code from viewWillAppear: to viewDidAppear: because the view is not in the view hierarchy at that point. Your solution might be a combination of these two issues.
hi there when i run my delegate method which is parsing json data the alert view appears to freeze whilst it is performing the method is there anyway to hide the alert view whilst the app is running the code I've tried
- (IBAction)btnAdd:(id)sender {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Add Source" message:#"Enter the web address of the json data" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Add", nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert setTag:0];
[alert dismissWithClickedButtonIndex:-1 animated:YES];
[alert show];
}
this doesn't actually do anything.
any advice?
*UPDATE
in the delegate method i get the same result
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag == 0) {
if (buttonIndex == 1) {
NSString *textEnteredraw = [[alertView textFieldAtIndex:0] text];
[alertView dismissWithClickedButtonIndex:-1 animated:YES];
From method
- (IBAction)btnAdd:(id)sender
Remove
[alert dismissWithClickedButtonIndex:-1 animated:YES];
Because as #Dima said, you are dismissing the alertView before you are even showing it.
You call the code to hide the alert before you even show it. This method is meant to be called after the alert is shown.
I have a segue that I want to be preformed when I push the Manual Entry and Scan Tag buttons on my AlertView.
#implementation triageViewController
- (IBAction)addNew:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Add A New Entry"
message:#"Choose a way to add a new entry."
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Manual Entry", #"Scan Tag", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != alertView.firstOtherButtonIndex) {
[self performSegueWithIdentifier:#"manual" sender: self];
}
if (buttonIndex != alertView.cancelButtonIndex) {
[self performSegueWithIdentifier:#"scan" sender: self];
}
}
(I realize this would probably make the cancel button preform a segue right now, but i'm more concerned with making it work)
I have the two segues in my storyboard, going from a UITabViewController to two different UIViewControllers. neither of these are being called, so when I tap them. I tried using both push and modal segues, but neither one was working.
I also tried the if/else statement like so:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
[self performSegueWithIdentifier:#"manual" sender: self];
}
if (buttonIndex == 1) {
[self performSegueWithIdentifier:#"scan" sender: self];
}
}
But this is not working either.
Could someone help me figure out what is going wrong? Again in case I was unclear, I want to preform a segue from a UIAlertView pop-up located on a UITabBarController to two separate UIViewControllers.
Thanks
It looks like your UIAlertView has a delegate of nil so your function is never being called. Set that to self and then in your view controller's header make sure you're implementing the UIAlertViewDelegate protocol.
This question already has an answer here:
UIAlertView not functioning correctly
(1 answer)
Closed 8 years ago.
I am trying to make a popup appear when the user clicks a button with a warning, and if they click cancel, it will be dismissed, but if they click continue, I want it to present the view controller. Here is my code, but it only dismisses the popup no matter which button I press:
- (IBAction)latest:(id)sender {
alert = [[UIAlertView alloc] initWithTitle:#"WARNING" message:#"Continuing will use internet and may cause app to slow down in large crowds" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Continue", nil];
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 2) {
UIViewController *NVC = [self.storyboard instantiateViewControllerWithIdentifier:#"Latest"];
[self presentViewController:NVC animated:YES completion:Nil];
}
}
Your problem is simple - you need to pass self as the alert view's delegate, not nil.
Also, in your delegate method, don't hard code button indexes. Do this instead:
if (buttonIndex == alertView.firstOtherButtonIndex) {
}
You only have 2 options to click. Indexes start at 0 not 1 so change if (buttonIndex == 2) to if (buttonIndex == 1)
Ok I figured it out. I had to set the delegate to self, it was set to "nil".
In my UIAlertView, I want to open another UIView when "OK" button is pressed.
But the problem is, even after the UIView is displayed, alert remains in screen and once it fades away, the UIView seems to be disabled.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Add details" message:#" Do you like to set the details now?" delegate:self cancelButtonTitle:#"Yes" otherButtonTitles:#"No",nil];
[alert show];
[alert release];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{ // the user clicked one of the OK/Cancel buttons
NSString *title = [alertView title];
if([title isEqualToString:#"Add details"])
{
.......
Any help would be appreciated!
Why not check for the button pressed in the delegate method instead of the title?
That is, in
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0){
// User pressed "YES"
}else{
// User pressed "NO"
}
}
The cancel button has index 0 and the other buttons increase in index. In order to detect which alert was this, you should also give it a tag. Hope this helps.
Could be because the new view is added before the alert view is actually dismissed. So better use the didDismissWithButtonIndex delegate to show a new view on button click event of an existing alert view, instead of clickedButtonAtIndex
- (void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
//Add the view
}
Instead of
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//Add the view
}