UIAlertView button action not working - ios

I have one alert view and when I click on yes button it is supposed to produce another alert view and a toast message,but it is not happening. I couldn't figure it out. Here is my code:
-(void)myMethod {
UIAlertView *saveAlert = [[UIAlertView alloc] initWithTitle:#"First Message"
message:#"My First message"
delegate:nil
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
saveAlert.tag=0;
[saveAlert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:NO];
}
This is the method I am using to provide the functionality for different alert views.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(alertView.tag==0) {
if (buttonIndex == 0)
{
//Code for Cancel button
}
if (buttonIndex == 1)
{
//code for yes button
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.mode = MBProgressHUDModeText;
hud.labelText = #"Successfully displayed First Message";
hud.margin = 10.f;
hud.yOffset = 150.f;
hud.removeFromSuperViewOnHide = YES;
[hud hide:YES afterDelay:3];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Second Message"
message:#"My second message"
delegate:nil
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes",nil];
alert.tag=1;
[alert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
}
}
if (alertView.tag==1) {
if (buttonIndex == 0)
{
//Code for Cancel button
}
if (buttonIndex == 1)
{
//Code for yes Button
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.mode = MBProgressHUDModeText;
hud.labelText = #"Succesfully displayed Second Message";
hud.margin = 10.f;
hud.yOffset = 150.f;
hud.removeFromSuperViewOnHide = YES;
[hud hide:YES afterDelay:3];
}
}
}
Can anyone help in finding the issue. Why I cannot get my second alert after clicking yes button in first alert?

You have not set the delegate for your UIAlertView and also make sure your delegate conforms to UIAlertViewDelegate protocol. Find the code snippet below.
You controller conforms to UIAlertViewDelegate protocol:
#interface YourViewController : UIViewController <UIAlertViewDelegate>
Create UIAlertView and set the deleagte:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"First Message"
message:#"Show second message"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[alertView show];
Implement UIAlertViewDelegate delegate method:
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if( 0 == buttonIndex ){ //cancel button
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
} else if ( 1 == buttonIndex ){
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
UIAlertView * secondAlertView = [[UIAlertView alloc] initWithTitle:#"Second Message"
message:#"Displaying second message"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[secondAlertView show];
}
}

You are specifying nil as the delegate for your alert views. You need to specify an object so the alertView:clickedButtonAtIndex: method can be called!

If you'd like to handle this more clear, you could use a block-based AlertView.
Create new file->Subclass of->UIAlertView
SuperAlertView.h
#import <UIKit/UIKit.h>
#class MySuperAlertView;
typedef void (^MySuperAlertViewBlock) (MySuperAlertView *alertView);
#interface MySuperAlertView : UIAlertView
- (instancetype) initWithTitle:(NSString *)title message:(NSString *)message;
- (void) addButtonWithTitle:(NSString *)buttonTitle block:(MySuperAlertViewBlock) block;
#end
SuperAlertView.m
#import "MySuperAlertView.h"
#interface MySuperAlertView()<UIAlertViewDelegate>
#property NSMutableArray *blocks;
#end
#implementation MySuperAlertView
- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message
{
if (self = [super initWithTitle:title message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil])
{
self.blocks = [NSMutableArray array];
}
return self;
}
- (void)addButtonWithTitle:(NSString *)buttonTitle block:(MySuperAlertViewBlock)block
{
[self addButtonWithTitle:buttonTitle];
[self.blocks addObject:block ? [block copy] : [NSNull null]];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
MySuperAlertViewBlock block = self.blocks[buttonIndex];
if ((id) block != [NSNull null]){
block(self);
}
}
#end
Usage:
MySuperAlertView *alertView = [[MySuperAlertView alloc] initWithTitle:#"Info" message:NSLocalizedString(#"EMAIL_SENT_SUCCESSFULL", nil)];
[alertView addButtonWithTitle:#"Ok" block:^(MySupertAlertView *alertView) {
// handle result from ok button here
}];
[alertView addButtonWithTitle:#"cancel" block:NULL];
dispatch_async(dispatch_get_main_queue(), ^{
[alertView show];
});

Related

Opening a new view controller after alert

enter code hereI am having trouble with going back to the previous view controller when alert is presented.
What I am trying to do is have the user enter in data, then an alert appear saying it was successful, then return to the previous view controller.
I currently have no code doing so and am seeking assistance with what I should put in.
- (IBAction)saveLabel:(id)sender
{
NSArray *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"DATA"];
NSMutableArray *currentDataArray;
if (data == nil)
{
currentDataArray = [[NSMutableArray alloc]init];
}
else
{
currentDataArray = [[NSMutableArray alloc]initWithArray:data];
}
[currentDataArray addObject:self.textField.text];
[[NSUserDefaults standardUserDefaults] setObject:currentDataArray forKey:#"DATA"];
}
- (IBAction)enterButtonPressed:(id)sender
{
NSLog(#"enterButtonPressed");
UIAlertView *enterAlert = [[UIAlertView alloc]initWithTitle:nil message:#"Entry was recorded" delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
[enterAlert show];
}
//If u r using dismissing
[self dismissViewControllerAnimated:YES completion:^{
UIAlertView *enterAlert = [[UIAlertView alloc]initWithTitle:nil message:#"Entry was recorded" delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
[enterAlert show];
}];
//if u r using navigation ,popViewController
[CATransaction begin];
[CATransaction setCompletionBlock:^{
// handle completion here
UIAlertView *enterAlert = [[UIAlertView alloc]initWithTitle:nil message:#"Entry was recorded" delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
[enterAlert show];
}];
[self.navigationController popViewControllerAnimated:YES];
[CATransaction commit];
Set Delegate self of your UIAlertView
UIAlertView *enterAlert = [[UIAlertView alloc]initWithTitle:nil message:#"Entry was recorded" delegate:self cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
[enterAlert show];
Use Delegate Method of UIAlertviewController.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex==0){
// Do your Stuff Here....
[self.navigationController popViewControllerAnimated:TRUE];
}
}
Add the following UIAlertViewDelegate method to your implementation file:
- (void)alertView:(UIAlertView *)alertView
didDismissWithButtonIndex:(NSInteger)buttonIndex {
// If you are presenting this view controller
[self dismissViewControllerAnimated:YES completion:nil];
// If you are pushing this view controller
[self.navigationController popViewControllerAnimated:YES];
}
Also remember to set your UIAlertView delegate to your view controller, change to the following code:
UIAlertView *enterAlert = [[UIAlertView alloc]initWithTitle:nil message:#"Entry was recorded" delegate:self cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
UIAlertView *enterAlert = [[UIAlertView alloc]initWithTitle:nil message:#"Entry was recorded" delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
enterAlert.tag=100;
[enterAlert show];
}
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (alertView.tag == 100) {
if (buttonIndex == 0) {
// Do something when ok pressed
// If you are presenting this view controller
[self dismissViewControllerAnimated:YES completion:nil];
// If you are pushing this view controller
[self.navigationController popViewControllerAnimated:YES];
} else {
// Do something for other alertviewButton}
else{// Do something with responses from other alertViews by giving tags
}

how to delay a popup page?

I just built an Activity indicator view, and a popup page in Xcode. How can I get a 3 second delay in Activity indicator view, then switch to popup page?
here is my Viewcontroller.m
- (IBAction)Connect:(UIButton *)sender forEvent:(UIEvent *)event
{
[self performSelector:#selector(delay2) withObject:Nil afterDelay:6.0];
[self performSelector:#selector(delay1) withObject:ConnectAct afterDelay:0.0];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"LP01;" message:#"No Connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Help", nil];
[alert show];
}
- (IBAction)ConnectLP02:(UIButton *)sender
{
[self performSelector:#selector(delay2) withObject:Nil afterDelay:6.0];
[self performSelector:#selector(delay1) withObject:ConnectAct afterDelay:0.0];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"LP02;" message:#"No Connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Help", nil];
[alert show];
}
- (void)delay1 {
ConnectAct.alpha = 1.0;
}
- (void)delay2 {
}
- (IBAction)ConnectLP02:(UIButton *)sender
{
[self performSelector:#selector(delay2) withObject:Nil afterDelay:6.0];
[self performSelector:#selector(delay1) withObject:ConnectAct afterDelay:0.0];
}
- (void)delay1 {
ConnectAct.alpha = 1.0;
}
- (void)delay2 {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"LP02;" message:#"No Connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Help", nil];
[alert show];
}

I have seven methods in which I am calling alert function, is it possible i do call only one time alert function, so to optimize my code

I have six methods, in which I'm calling alert function.
Is it possible to call only the alert function only once, so to optimize my code will be?
This is my code:
// #import "ViewController.h"
//.h file
.m file
#interface ViewController ()
#end
#implementation ViewController
#synthesize usernameText;
#synthesize emailText;
#synthesize passwordText;
#synthesize `repasswordTex`t;
#synthesize postalText;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
//for keyboard hide on textfield return
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
[theTextField resignFirstResponder];
return YES;
}
//function for Name validation
- (BOOL) validatename:(NSString *) candidate{
[postalText setKeyboardType:UIKeyboardTypeAlphabet];
NSString *nameRegex = #"[A-Za-z]+";
NSPredicate *codeTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",nameRegex];
return [codeTest evaluateWithObject:candidate];
}
// email validation
- (BOOL) validateEmail: (NSString *) candidate {
NSString *emailRegex = #"[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex];
return [emailTest evaluateWithObject:candidate];
}
// password code validation
- (BOOL)paswordvalidation:(NSString *) candidate
{
}
// postal code validation
- (BOOL) validatecode: (NSString *) candidate {
NSString *codeRegex = #"^\d{5}(?:[-\s]\d{4})?$";
NSPredicate *codeTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", codeRegex];
return [codeTest evaluateWithObject:candidate];
}
//method call on submit button
- (IBAction)submitButn:(id)sender{
//user name method call
if(![self validatename:usernameText.text])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Please Ensure that you have insert character only"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
//Email Method Call
else if(![self validateEmail:emailText.text])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Please Insert Valid Email Address"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
//Password validate Method Call
else if([passwordText.text length] <6)//&& [repasswordText.text length] <= 6)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Password should contain minimun 6 "delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
else if (![passwordText.text isEqualToString:repasswordText.text])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"confirm password should be same"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
//Postal Code Method Call
else if(!([self validatecode:postalText.text] ||[postalText.text length] <6))
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"postal Code should cotain 5 "delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Write this method and call where ever you want.
-(void)showAlert :(NSString *)alertTitleString WithAlertMessage :(NSString *)alertMessage{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:alertTitleString alertMessage delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
It is possible, add this method name in AppDelegate.h
-(void)alertFuction:(NSString *)title message:(NSString *)message
Then add this function to AppDelegate.m
-(void)alertFuction:(NSString *)title message:(NSString *)message
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:title message:message delegate:self cancelButtonTitle:#"Done" otherButtonTitles:nil, nil];
[alert show];
[alert release];
alert = nil;
[delegate.window setUserInteractionEnabled:YES];
}
Then in any other view controller put this
.h file
#class AppDelegate
.m file
#import AppDelegate
in viewDidload method
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
then you can call the alert method by
[delegate alertFuction:#"title" message:#"message"];
How about a generalised helper class with class methods which cover a number of common scenarios (which you may obviously want to reconfigure / add to):
#implementation AlertHelper
+ (UIAlertView *)showAlertWithMessage:(NSString *)message
{
[AlertHelper showAlertWithTitle:nil message:message delegate:nil cancelButton:NSLocalizedString(#"OK", nil) otherButton:nil];
}
+ (UIAlertView *)showAlertWithTitle:(NSString *)title message:(NSString *)message
{
[AlertHelper showAlertWithTitle:title message:message delegate:nil cancelButton:NSLocalizedString(#"OK", nil) otherButton:nil];
}
+ (UIAlertView *)showAlertWithTitle:(NSString *)title message:(NSString *)message delegate:(id < UIAlertViewDelegate >)delegate cancelButton:(NSString *)cancel otherButton:(NSString *)other
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:delegate cancelButtonTitle:cancel otherButtonTitles:(other ? #[ other ] : nil)];
[alert show];
}
#end
Note that the alert view is returned just in case it is required (say you need to automatically remove the alert view once an operation is complete).
Surely you can, you even should! You just need to refactor it to a separate methods witch will receive a few attributes or (better option) an object with variables from which you could set a required values for the alert you want to show.
- (void)showAlertWithTitle:(NSString *)alertTitle andMessage:(NSString *)alertMessage {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:alertTitle message:alertMessage delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
It could be than a way better but according to your case that will do what you want. It is just extracting a method from your code.

UIAlertView keeps re-appearing after dismissWithClickedButtonIndex included in performSelector: withObject: afterDelay:

I have a button which I want to implement with password before triggering a segue if the password is correct. it all looks fine up to the moment when you type in wrong password and I have implemented another alertView to tell the user the password is wrong. When the alert view pops out and dismisses after some delay, it keeps re-appearing and disappearing and nothing else can be done on the screen!
How to stop the re appearing?
Below is my part of the code that deals with this:
- (IBAction)editLeagues:(id)sender {
[self presentAlertViewForPassword];
}
-(void)presentAlertViewForPassword
{
_passwordAlert = [[UIAlertView alloc]initWithTitle:#"Password"
message:#"Enter Password to edit Leagues"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
[_passwordAlert setAlertViewStyle:UIAlertViewStyleSecureTextInput];
_passwordField = [_passwordAlert textFieldAtIndex:0];
_passwordField.delegate = self;
_passwordField.autocapitalizationType = UITextAutocapitalizationTypeWords;
_passwordField.tag = textFieldPassword;
[_passwordAlert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSString *password = [NSString stringWithFormat:#"55555"];
if ( ![_passwordField.text isEqual:password]) {
_wrongPassword = [[UIAlertView alloc] initWithTitle:#"Wrong Password"
message:#"You are not authorised to use this feature!"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
[_wrongPassword show];
[self performSelector:#selector(allertViewDelayedDissmiss:) withObject:nil afterDelay:2];
}
else
{
[self performSegueWithIdentifier:#"addLeague" sender:[alertView buttonTitleAtIndex:0]];
}
}
-(void) allertViewDelayedDissmiss:(UIAlertView *)alertView
{
[_wrongPassword dismissWithClickedButtonIndex:-1 animated:YES];
}
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
NSString *inputText = [[alertView textFieldAtIndex:0] text];
if( [inputText length] >= 4 )
{
return YES;
}
else
{
return NO;
}
}
[_wrongPassword dismissWithClickedButtonIndex:-1 animated:YES]; will call the delegate method alertView:didDismissWithButtonIndex:
You have two options:
don't set a delegate on the wrong password alert
check for the correct alert in alertView:didDismissWithButtonIndex: e.g.
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (alert == _passwordAlert) {
NSString *password = [NSString stringWithFormat:#"55555"];
// and so on
}
}
Issue is causing because when you dismiss the wrong password alert it'll also call the didDismissWithButtonIndex delegate method.
Solution 1
Set the delegate of wrong password alert to nil.
wrongPassword = [[UIAlertView alloc] initWithTitle:#"Wrong Password"
message:#"You are not authorised to use this feature!"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:nil];
Solution 2
Add a tag to your alertView. And change your methods like:
-(void)presentAlertViewForPassword
{
_passwordAlert = [[UIAlertView alloc]initWithTitle:#"Password"
message:#"Enter Password to edit Leagues"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
[_passwordAlert setAlertViewStyle:UIAlertViewStyleSecureTextInput];
passwordAlert.tag = 7;
_passwordField = [_passwordAlert textFieldAtIndex:0];
_passwordField.delegate = self;
_passwordField.autocapitalizationType = UITextAutocapitalizationTypeWords;
_passwordField.tag = textFieldPassword;
[_passwordAlert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if(alertView.tag == 7)
{
NSString *password = [NSString stringWithFormat:#"55555"];
if ( ![_passwordField.text isEqual:password])
{
_wrongPassword = [[UIAlertView alloc] initWithTitle:#"Wrong Password"
message:#"You are not authorised to use this feature!"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
[_wrongPassword show];
[self performSelector:#selector(allertViewDelayedDissmiss:) withObject:nil afterDelay:2];
}
else
{
[self performSegueWithIdentifier:#"addLeague" sender:[alertView buttonTitleAtIndex:0]];
}
}
}

NSOperaionQueue and UIAlertView

The problem is that if I create and display two alert - the second will override the first, and after it closed displayed first. So not pretty.
I'm trying to create a queue alerts with NSOperationQueue. That you could add a few alerts and they show a sequence to close. But I can not do so would be that I add operations are performed sequentially, waiting for the previous one. They are executed in parallel.
AlertOperation.h
#import <Foundation/Foundation.h>
#interface AlertOperation : NSOperation<UIAlertViewDelegate>
#property (nonatomic,assign) BOOL isFinishedAlert;
- (AlertOperation *)initWithAlert:(UIAlertView *)alert;
#end
AlertOperation.m
#import "AlertOperation.h"
#interface AlertOperation()
{
UIAlertView *_alert;
}
#end
#implementation AlertOperation
#synthesize isFinishedAlert = _isFinishedAlert;
- (AlertOperation *)initWithAlert:(UIAlertView *)alert
{
self = [super init];
if (self)
{
_alert = alert;
_alert.delegate = self;
[_alert show];
}
return self;
}
- (void) main
{
_isFinishedAlert = NO;
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!_isFinishedAlert);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
_isFinishedAlert = YES;
}
- (BOOL) isConcurrent
{
return NO;
}
#end
Here is run code
UIAlertView *u1 = [[UIAlertView alloc] initWithTitle:#""
message:#"Hello i am first alert" delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
UIAlertView *u2 = [[UIAlertView alloc] initWithTitle:#""
message:#"Hello i am second alert" delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
NSOperation *alertOp1 = [[AlertOperation alloc] initWithAlert:u1];
NSOperation *alertOp2 = [[AlertOperation alloc] initWithAlert:u2];
alertsQueue = [[NSOperationQueue alloc] init];
[alertsQueue setMaxConcurrentOperationCount:1];
[alertsQueue addOperation:alertOp1];
[alertsQueue addOperation:alertOp2];
Make this easier on yourself. Create a mutable array. When you have new alerts to show then push them onto the array. Every time an alert finishes (gets its delegate message), then dispatch the next alert onto the main queue:
NSMutableArray *alerts;
... end of Alert Delegate message
if([alert count]) {
UIAlert *alrt = [alerts objectAtIndex:0];
[alerts removeObjectAtIndex:0];
dispatch_async(dispatch_get_main_queue(), ^{ [alrt show]; } );
}
I moved the [_alert show] to -(void)main method and it worked! Thank you, #phix23 for help!

Resources