is there easy way to handle UIAlertView result without delegation?

17,781

Solution 1

There is no way to avoid delegation completely, but you could create a wrapper to that effect along these lines:

@interface MyAlertViewDelegate : NSObject<UIAlertViewDelegate>

typedef void (^AlertViewCompletionBlock)(NSInteger buttonIndex);
@property (strong,nonatomic) AlertViewCompletionBlock callback;

+ (void)showAlertView:(UIAlertView *)alertView withCallback:(AlertViewCompletionBlock)callback;

@end


@implementation MyAlertViewDelegate
@synthesize callback;

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

+ (void)showAlertView:(UIAlertView *)alertView
         withCallback:(AlertViewCompletionBlock)callback {
    __block MyAlertViewDelegate *delegate = [[MyAlertViewDelegate alloc] init];
    alertView.delegate = delegate;
    delegate.callback = ^(NSInteger buttonIndex) {
        callback(buttonIndex);
        alertView.delegate = nil;
        delegate = nil;
    };
    [alertView show];
}

@end

(ARC is assumed, if you are not using it change delegate = nil to [delegate release].)

Usage would be something like:

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Confirm" message:@"Yes or No?" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:@"Yes",@"No", nil];
[MyAlertViewDelegate showAlertView:alert withCallback:^(NSInteger buttonIndex) {
    // code to take action depending on the value of buttonIndex
}];

Solution 2

I have written a blog post about how to (and why) add block callbacks to alert views, action sheets and animations:

http://blog.innovattic.com/uikitblocks/

If you just want a working implementation of this you can download the sources files from GitHub:

https://github.com/Innovattic/UIKit-Blocks

Usage:

UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"My easy alert"  
                                                message:@"Would you like to perform some kind of action?"
                                      cancelButtonTitle:@"No"
                                      otherButtonTitles:@"Yes", nil];
[alert setHandler:^(UIAlertView* alert, NSInteger buttonIndex) {
    NSLog(@"Perform some kind of action");
} forButtonAtIndex:[alert firstOtherButtonIndex]];
[alert show];

Solution 3

It's very easy. Say you have an alert, something like this:

//Alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Confirm" message:@"Yes or No?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Yes",@"No", nil];
[alert show];

You're going to need to add this method:

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

A possible implementation of this method would look like this:

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

//Checks For Approval
    if (buttonIndex == 1) {
        //do something because they selected button one, yes
    } else {
        //do nothing because they selected no
    }
}
Share:
17,781
jAckOdE
Author by

jAckOdE

A progreamer

Updated on July 27, 2022

Comments

  • jAckOdE
    jAckOdE almost 2 years

    I have a function that shows a UIAlertView with YES/NO buttons, and it is used only inside the function's scope so I dont want to implement a delegation to catch the user feedback.

    Is there any way to know what button users clicked without implement UIAlertViewDelegate, something like:

    [alert show];
    if([alert indexOfClickedButton] == indexOfYes)
    {
    ....
    }
    

    Or lambda expression as in Animation

  • Arkku
    Arkku about 12 years
    But he specifically asked how to do it without delegation
  • jAckOdE
    jAckOdE about 12 years
    Thank! And yes, it will save me some line of codes, but i still have to write some code outside of the function's scope and, probably, save a reference of the alertview, that is what I dont want. I'm looking for a block-based solution, and if there is no simple way to do that, I think your solution would be the best.
  • Jtaylorapps
    Jtaylorapps about 12 years
    Glad I was able to help out some!
  • Peter Warbo
    Peter Warbo almost 12 years
    I'm getting a compiler warning on the line where you do delegate = nil saying : Capturing delegate strongly in this block is likely to lead to a retain cycle. This under iOS 5.1 ARC.
  • AndiDog
    AndiDog over 10 years
    delegate = nil is necessary because alertView.delegate is a non-retaining property and we need to keep the object "delegate" until the alert view is button callback is finished. The warning (a false positive) can be ignored with #pragma clang diagnostic push and #pragma clang diagnostic ignored "-Warc-retain-cycles" before, and #pragma clang diagnostic pop after that line.
  • Ferran Maylinch
    Ferran Maylinch about 10 years
    Great, thank! You can just pass delegate:nil when creating the alert.
  • Arkku
    Arkku almost 9 years
    2015 update: UIAlertView is deprecated and its replacement, UIAlertController, allows adding actions with UIAlertAction, which takes a block as action handler.
  • rakeshNS
    rakeshNS over 8 years
    @jAckOdE if you do not want to keep a reference for alert view object, you can use tags for alert view. example, alert = 101; and in - (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex, you can check , if alert.tag == 101 {}....