21

Say I have a alert view like follows in obj c

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"title" message:@"szMsg" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:@"download"];
        [alert show];
        [alert release];

Now we have 2 buttons on the alert view (Ok & Download), how to write an event handler for the Download one?

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
Ravi
  • 1,759
  • 5
  • 20
  • 38
  • u can use delegate methods of alertview. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if(buttonIndex==0) //ok button action if(buttonIndex==1) //download button action } for this method to be called set delegate of ur alertview to self. – cancerian Sep 13 '11 at 05:20
  • http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html – Praveen-K Sep 13 '11 at 05:21

8 Answers8

46

First you will need to add the UIAlertViewDelegate to your header file like below:

Header file (.h)

@interface YourViewController : UIViewController<UIAlertViewDelegate> 

Implementation File (.m)

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"title" message:@"szMsg" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:@"download"];
        [alert show];
        [alert release];

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 0)
    {
        //Code for OK button
    }
    if (buttonIndex == 1)
    {
        //Code for download button
    }
}
Flea
  • 11,176
  • 6
  • 72
  • 83
Chetan Bhalara
  • 10,326
  • 6
  • 32
  • 51
  • 1
    suppose in the .m file i have 10 uialerts and two buttons in each then for which alert the above method ill be used? – Ravi Sep 13 '11 at 05:52
  • Whenever you create any UIAlertView you need to set delegate for that either you use self or nil. If you use self in delegate then it call this method and when you use nil in delegate then it not call this method. – Chetan Bhalara Sep 13 '11 at 05:59
  • fine,,say i have 2 uialerts and delegate set to self in both the cases and first uialert contains (ok & download)buttons second contains (cancel & upload)buttons now we need separate event handlers know? – Ravi Sep 13 '11 at 06:04
  • 1
    If u have more than two uialertviews and all are having delegate = self.. Then well in that case assign each alertview a separate "tag". according to that tag (if(alertView.tag == urTagname)) do ur needs. – Abdul Yasin Sep 20 '13 at 13:24
  • what about now that it's been deprecated? – Marin Dec 10 '20 at 09:28
5

Now that most iOS devices have firmare versions with blocks support it’s an anachronism to use the clumsy callback API to handle button presses. Blocks are the way to go, see for example the Lambda Alert classes on GitHub:

CCAlertView *alert = [[CCAlertView alloc]
    initWithTitle:@"Test Alert"
    message:@"See if the thing works."];
[alert addButtonWithTitle:@"Foo" block:^{ NSLog(@"Foo"); }];
[alert addButtonWithTitle:@"Bar" block:^{ NSLog(@"Bar"); }];
[alert addButtonWithTitle:@"Cancel" block:NULL];
[alert show];
zoul
  • 102,279
  • 44
  • 260
  • 354
  • 1
    And nowadays it finally is with [UIAlertController](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/). – zoul Jan 19 '15 at 16:43
  • So no need for delegates now? – Marin Dec 10 '20 at 09:29
2

Stack's and Guillermo Ortega's answer is probably what you would use with a couple of UIAlertView but not for ten. I use to use BlocksKit which is kind of the same as Lambda stuff which is what soul suggested. That is a good option too, although if you have too many nested blocks you will start seeing the demerits of it (Aside from the fact you will be relying in another library).

The usual way of handling several stuff would be to have a handler object. ( @interface MyAlertViewDelegate : NSObject <UIAlertViewDelegate> @end) make that object the delegate of the alert view and make sure the object is alive at least until the alert view is dismissed. This will certainly work, but could be too much work...

What follows is what I came up with; IMO it is simpler and there is no need of any thirdParty library, or an ivar per UIAlertView. Just one extra object (@property (nonatomic, strong) NSArray *modalActions) to store the actions the current UIAlertView will cause to perform

Showing an UIAlertView and reacting accordingly

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle
                                                    message:@"Blah blah"
                                                   delegate:self
                                          cancelButtonTitle:@"Cancel"
                                          otherButtonTitles:b1, b2, b3, nil];
// Add one selector/action per button at the proper index
self.modalActions = @[
                   [NSNull null], // Because indexes of UIAlertView buttons start at 1
                   NSStringFromSelector(@selector(actionForAlertViewButton1)),
                   NSStringFromSelector(@selector(actionForAlertViewButton2)),
                   NSStringFromSelector(@selector(actionForAlertViewButton3))];
[alertView show];

The delegate method:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (alertView.cancelButtonIndex != buttonIndex) {
        [self performModalActionAtIndex:buttonIndex];
    }
}

The part that actually performs the action:

- (void)performModalActionAtIndex:(NSInteger)index
{
    if (-1 < index && index < self.modalActions.count &&
        [self.modalActions[index] isKindOfClass:[NSString class]]) {
        SEL action = NSSelectorFromString(self.modalActions[index]);
        NSLog(@"action: %@", self.modalActions[index]);
        if ([self respondsToSelector:action]) {
// There is a situation with performSelector: in ARC.
// http://stackoverflow.com/questions/7017281/
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self performSelector:action];
#pragma clang diagnostic pop
    }
    self.modalActions = nil;
}

Reusable for UIActionSheets too

UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:title
                                                         delegate:self
                                                cancelButtonTitle:cancelButton  
                                           destructiveButtonTitle:nil 
                                                otherButtonTitles:button1, button2, button3, nil];
// Similarly, add one action per button at the proper index
self.modalActions = @[
                    NSStringFromSelector(@selector(actionForActionSheetButton1)),
                    NSStringFromSelector(@selector(actionForActionSheetButton2)),
                    NSStringFromSelector(@selector(actionForActionSheetButton3))];

The delegate method:

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (actionSheet.cancelButtonIndex != buttonIndex) {
        [self performModalActionAtIndex:buttonIndex];
    }
}

Why this works:

This works because of two reasons:

First, I never present two UIAlertView that have a delegate at the same time. (IMO you should't, it doesn't look good). Second, because in my case (as 90% of the cases) the target of the actions is always the same object (in this case: self). Even if you don't meet above conditions you can even use this approach with some modifications:

  • If you show two or more UIAlerViews or UIActionSheets at the same time (possible in the iPad) Use a dictionary with to store one array of actions associated with a certain UIAlertView/UIActionSheet.

  • If the target of the actions is not self, they you need to store pairs (target and the action) in the array. (Something to simulate UIButtons addTarget:action:...).

In either case, for storing the target and/or UIActionSheet/UIAlertView [NSValue valueWithNonretainedObject:] should become handy :)

nacho4d
  • 43,720
  • 45
  • 157
  • 240
2

Declare your UIAlertViews as known.

UIAlertView *alertLogout=[[UIAlertView alloc]initWithTitle:@"Title" message:@"Stop Application?" delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes",nil]; 

[alertLogout show]; 

[alertLogout release];

set delegate to self and implement this method.

-(void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    if(actionSheet== alertLogout) {//alertLogout
        if (buttonIndex == 0){

        }else if(buttonIndex==1){

        }
    }else if (actionSheet==alertComment) {//alertComment
        if (buttonIndex==0) {

        }
    }
}
1
First of all you declare UIAlertViewDelegate in .h file after put below code in .m file

- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex 
{

   if (buttonIndex == 1) 
    {
         //put button action which you want.
    }
}
Nikunj Jadav
  • 3,417
  • 7
  • 38
  • 54
0
UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:@"Data Saved" message:@"Choose more photos" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:Nil];
        [alertView show];
        [alertView release];


-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    if(buttonIndex==0)
    {
        [self dismissModalViewControllerAnimated:YES];
    }
}
kleopatra
  • 51,061
  • 28
  • 99
  • 211
0

in swift: we can use this little block of code

    let alert = UIAlertController(title: "Alert", message: "This is an alert message", preferredStyle: UIAlertControllerStyle.Alert)

    let action = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: {(action:UIAlertAction) in print("This is in alert block")
    })

    alert.addAction(action)
    self.presentViewController(alert, animated: true, completion: nil)
Tanvir Nayem
  • 702
  • 10
  • 25
0

Implement the UIAlertViewDelegate and make use of the delegate method

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  if(buttonIndex == 0) {
    // Do something
  }
  else {
   // Do something
  }
}
visakh7
  • 26,380
  • 8
  • 55
  • 69