1

Hi I wrote the following code:

    - (IBAction)DelBlockB:(id)sender {
    confirmDelB = [[UIAlertView alloc] initWithTitle:@"Attention" message:[NSString stringWithFormat:@"are you sure you want to delete and block %@", idnameArr[2]] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Cancel", nil];
    [confirmDelB show];
}

- (IBAction)DelFB:(id)sender {
    confirmDel = [[UIAlertView alloc] initWithTitle:@"Attention" message:[NSString stringWithFormat:@"are you sure you want to delete %@", idnameArr[2]] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Cancel",nil];

    [confirmDel show];
}

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

    if (buttonIndex == 0) {
        NSLog(@"ok");
    }
    else {
        NSLog(@"cancel");
    }
}

where the method "clickedButtonAtIndex" will return an answer no matter what UIAlertView was Pressed, how can I show an answer only if one of the alert was clicked ?

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • 1
    Use the new [UIAlertController](https://developer.apple.com/Library/ios/documentation/UIKit/Reference/UIAlertController_class/index.html#//apple_ref/occ/instm/UIAlertController/addAction:). It lets you add actions instead of wiring up delegates. – CrimsonChris Sep 29 '14 at 16:19
  • @CrimsonChris ok, that's awesome. I didn't know about that, thanks. However, my answer still holds if you want to support iOS7 :D – Fogmeister Sep 29 '14 at 16:28
  • You can still support blocks if you subclass `UIAlertView` is iOS7. – CrimsonChris Sep 29 '14 at 16:29
  • @CrimsonChris true except for the fact that the docs pretty much say "Don't subclass UIAlertView". – Fogmeister Sep 29 '14 at 16:30
  • Here's a solution available on github. https://github.com/ryanmaxwell/UIAlertView-Blocks – CrimsonChris Sep 29 '14 at 16:31
  • Actually, just thinking this through. You shouldn't really be using UIAlertView for this at all. UIAlertView is not supposed to be used for asking the user for input on an action. The correct thing to use is UIActionSheet in this case. (Following the Apple HIG). – Fogmeister Sep 29 '14 at 16:32
  • @Fogmeister I've never seen any docs that discourage subclassing UIAlertView. – CrimsonChris Sep 29 '14 at 16:33
  • @CrimsonChris Apple's docs on UIAlertView - Subclassing Notes. `The UIAlertView class is intended to be used as-is and does not support subclassing.` https://developer.apple.com/LIBRARY/IOS/documentation/UIKit/Reference/UIAlertView_Class/index.html – Fogmeister Sep 29 '14 at 16:34
  • If you don't feel comfortable subclassing to add some block properties you could instead add those blocks as associated objects. (Just noticed, this is actually what the github category linked above is doing) – CrimsonChris Sep 29 '14 at 16:37
  • possible duplicate of [Block for UIAlertViewDelegate](http://stackoverflow.com/questions/10082383/block-for-uialertviewdelegate) – CrimsonChris Sep 29 '14 at 16:48

4 Answers4

2
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

is a delegate method for UIAlertView you can't change which method is called per alert view. However, there is nothing stopping you from inspecting the alert view (it is passed in after all).

On each alert view...

Read past this. I really don't like using the tag property like this.

confirmDelB.tag = 1;
confirmDel.tag = 2;

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (alertView.tag == 1) {
        // This is confirmDelB.
    } else {
        // This is confirmDel.
    }
}

This is a much more elegant solution.

However, I HATE the use of tag. What I would do (possibly) is create an alertView property.

@property (nonatomic, strong) UIAlertView *deleteAndBlockAlertView;
@property (nonatomic, strong) UIAlertView *deleteOnlyAlertView;

Then use a method like...

- (UIAlertView *)deleteAndBlockAlertViewWithObject:(id)object
{
    if (!_deleteAndBlockAlertView) {
        confirmDelB = [[UIAlertView alloc] initWithTitle:@"Attention"
                                                 message:@""
                                                delegate:self
                                       cancelButtonTitle:@"OK"
                                       otherButtonTitles:@"Cancel", nil];
    }

    _deleteAndBlockAlertView.message = [NSString stringWithFormat:@"are you sure you want to delete and block %@", object];

    return _deleteAndBlockAlertView;
}

And the same for the other.

Now you can show it like...

- (IBAction)delBlockB:(id)sender
{
    [[self deleteAndBlockAlertViewWithObject:idnameArr[2]] show];
}

And in the delegate method...

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (alertView == self.deleteAndBlockAlertView) {
        // This is confirmDelB.
    } else {
        // This is confirmDel.
    }
}

This is a much more elegant solution in my opinion. And you only ever need to create each alert view once.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • It would be better if you didn't have the branches in the delegate. It gets very complicated if you've got a large number of possible alert views. – CrimsonChris Sep 29 '14 at 16:47
1

Add a tag to each alertView and check the tag value inside the delegate call.

- (IBAction)DelBlockB:(id)sender 
{
    confirmDelB = [[UIAlertView alloc] initWithTitle:@"Attention" message:[NSString stringWithFormat:@"are you sure you want to delete and block %@", idnameArr[2]] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Cancel", nil];
    confirmDelB.tag = 666;

    [confirmDelB show];
}

- (IBAction)DelFB:(id)sender {
    confirmDel = [[UIAlertView alloc] initWithTitle:@"Attention" message:[NSString stringWithFormat:@"are you sure you want to delete %@", idnameArr[2]] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Cancel",nil];
    confirmDelB.tag = 667;

    [confirmDel show];
}

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

    if (alertView.tag == 666) {
        // Do something
    }
    else {
        // Do something else
    }
}
Alfie Hanssen
  • 16,964
  • 12
  • 68
  • 74
  • 2
    Glad this helped. Regarding debate here about tags etc being outdated, storing alerts in properties, using blocks. The tag approach is the simplest approach, requires least additional code / complexity. And the idea that they're "outdated" doesn't really make sense. They've been around forever, but they're not deprecated or frowned upon - they're designed for just this use case. – Alfie Hanssen Sep 29 '14 at 16:34
  • This solution doesn't scale well. It's hard to logically follow in anything more complex than this trivial case. – CrimsonChris Sep 29 '14 at 16:45
  • 1
    There are lots of ways to burn yourself with tags. For example, do you know that no internal UIAlertView code sets its tag? – Jesse Rusak Sep 29 '14 at 16:57
  • The easiest solution can be the wrong one when working on production code. Make the extra effort to keep your code clean. The person who inherits your code base will thank you. – CrimsonChris Sep 29 '14 at 21:35
1

before show your alert

 myAlertView.tag = 0 // different number for different alertView

inside clickedButtonAtIndex:

if (alertView.tag == 0){
  //alert zero stuff and buttonIndex if
}
if (alertView.tag == 1){
  //alert one stuff and buttonIndex if
}
Totka
  • 627
  • 6
  • 24
1

Using blocks is a preferred approach to delegates+tags, both of which are terrible and outdated. Consider using the following method.

//Could be a category method!
- (void)presentAttentionAlertWithOkayBlock:(CompletionBlock)okayBlock {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Attention" message:@"" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancelAction = [UIAlertAction
                                   actionWithTitle:@"Cancel"
                                   style:UIAlertActionStyleCancel
                                   handler:^(UIAlertAction *action) {
                                       NSLog(@"Cancel action");
                                   }];
    UIAlertAction *okAction = [UIAlertAction
                               actionWithTitle:@"OK"
                               style:UIAlertActionStyleDefault
                               handler:^(UIAlertAction *action) {
                                   NSLog(@"OK action");
                                   if (okayBlock) okayBlock();
                               }];

    [alertController addAction:cancelAction];
    [alertController addAction:okAction];
    [self presentViewController:alertController animated:YES completion:nil];
}

This allows a clear separation between what each alert is going to do when the user clicks "okay". Also, people reading your code don't have to go hunting down that darn delegate method to see what the alert will do!

- (IBAction)DelBlockB:(id)sender {
    [self presentAttentionAlertWithOkayBlock:^{
        //Do something
    }];
}

- (IBAction)DelFB:(id)sender {
    [self presentAttentionAlertWithOkayBlock:^{
        //Do something else
    }];
}
CrimsonChris
  • 4,651
  • 2
  • 19
  • 30
  • 1
    "Terrible and outdated" is subjective and a extreme. Delegates are terrible / outdated? Tags are the most light weight approach to this question. And as long as they're not deprecated, there's no harm. – Alfie Hanssen Sep 29 '14 at 16:38
  • There is a reason why UIAlertView is now deprecated and being replaced with a solution that uses blocks instead. – CrimsonChris Sep 29 '14 at 16:40
  • If delegates and tags are "terrible and outdated" then so is Objective-C and you should be doing everything in Swift :P However, +1 for pointing out an awesome new iOS8 thing that I didn't know about. – Fogmeister Sep 29 '14 at 16:40
  • This blog helps explain why you don't want to be using delegates for something like alert views. http://nscookbook.com/2013/04/ios-programming-recipe-22-simplify-uialertview-with-blocks/ – CrimsonChris Sep 29 '14 at 16:43