Search code examples
ioscallbackindexingcustom-controlsuialertview

Custom UIAlertView no delegate callback?


I just recently implemented: https://github.com/gpambrozio/BlockAlertsAnd-ActionSheets

I have imported all the necessary files into my app and compiles fine. Now the issue is, how do I deal with the logic change?

So before with Apple's UIAlertView I did something like this:

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Which Key?" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
            for (NSMutableDictionary *dict in myArray) {
                [alertView addButtonWithTitle:[dict objectForKey:@"Key"]];
            }
 [alertView show];
 [alertView release];

Then in the alertview's callback I would do this:

- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    [[Singleton sharedSingleton] setKey:buttonIndex];
}

Now with the BlockAlertView there is no callback for which button has been pressed, how they handle a button press is to put the code you want to execute in the block like I show below. Anyway this is how a similar BlockAlertView would look:

BlockAlertView *alertView = [BlockAlertView alertWithTitle:@"Which Key?" message:nil];
            for (NSMutableDictionary *dict in myArray) {
                [alertView addButtonWithTitle:[dict objectForKey:@"Key"] block:^{
                    //Not sure what to do here
                }];
            }
[alertView show];

Now here is what I do not know what to do, in that block how do I achieve what I did before with Apple's native UIAlertView? I can't access the button index and I can't access the name of the button either (not like that would help in my case anyway since I need the index)

Anyway, how should I go upon doing what I did with Apple's native UIAlertView but with the BlockAlertView's logic?

Thanks!

Edit1 @Christian Pappenberger:

This is the .h of BlockAlertView and I don't think there is a protocol I can add to unless I'm wrong. Here it is:

@interface BlockAlertView : NSObject {
@protected
    UIView *_view;
    NSMutableArray *_blocks;
    CGFloat _height;
}

+ (BlockAlertView *)alertWithTitle:(NSString *)title message:(NSString *)message;

- (id)initWithTitle:(NSString *)title message:(NSString *)message;

- (void)setDestructiveButtonWithTitle:(NSString *)title block:(void (^)())block;
- (void)setCancelButtonWithTitle:(NSString *)title block:(void (^)())block;
- (void)addButtonWithTitle:(NSString *)title block:(void (^)())block;

- (void)show;
- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated;

@property (nonatomic, retain) UIImage *backgroundImage;
@property (nonatomic, readonly) UIView *view;
@property (nonatomic, readwrite) BOOL vignetteBackground;

@end

Solution

  • A block is a portion of code that will be executed once it is triggered.

    [alertView addButtonWithTitle:[dict objectForKey:@"Key"] block:^{
                        //Not sure what to do here
                    }];
    

    The code above adds a button to the BlockAlertView and once it is pressed, the code that's in the block it's what is going to be executed. Here's an example:

    ...
    
    [alertView addButtonWithTitle:@"First Button" block:^{
                        NSLog(@"First Button Pressed");
                    }];
    
    [alertView addButtonWithTitle:@"Second Button" block:^{
                        NSLog(@"Second Button Pressed");
                    }];
    ...
    
    [alertView show];
    

    Once the code is executed and the alertView is shown, two buttons will be present in the alertView, with titles "First Button" and "Second Button". When you click each of the buttons, what will happen is that the code in the block will be executed. The console will output "First Button Pressed" or "Second Button Pressed" depending on the button pressed.

    Now that you know how this type of alertViews work I'll explain what you need to do in your case.

    As you point out you wont get the buttonIndex, but you will know which button triggered the block.

    So if you need to now the buttonIndex I would add an int buttonIndex and increment it each time as in the code below:

    BlockAlertView *alertView = [BlockAlertView alertWithTitle:@"Which Key?" message:nil];
    
        int buttonIndex = 0; // HERE
    
        for (NSMutableDictionary *dict in myArray) {
           [alertView addButtonWithTitle:[dict objectForKey:@"Key"] block:^{
                    [[Singleton sharedSingleton] setKey:buttonIndex]; // HERE
               }];
    
        buttonIndex++; // HERE
                        }
    
            [alertView show];
    

    If you need further explanation of something else feel free to ask.

    EDIT Added explanation

    The block paradigm differs with the delegate paradigm. With the delegate paradigm when the button is pressed it will call the delegate method (clickedButtonAtIndex:) in the UIAlerViewDelegate case. When a block gets executed, each separate block is triggered.

    Here's the key:

    When you use the block approach each button owns the code it will execute once its triggered. In the delegate approach when buttons are pressed they will call a common method to be executed.

    So in an example:

    Goal: Output to the console different words depending on the button pressed.

    Delegate approach:

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Which Key?" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
    
    [alertView addButtonWithTitle:"@Button 1"];
    [alertView addButtonWithTitle:"@Button 2"];
    [alertView addButtonWithTitle:"@Button 3"];
    
    [alertView show];
    
    - (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
        if(buttonIndex == 0)
           NSLog(@"Dog");
        else if (buttonIndex == 1)
           NSLog(@"Cat");
        else if (buttonIndex == 2)
           NSLog(@"Shark");
    }
    

    As you can see, once the button is pressed, the delegate method is called and there is when you decide depending on the buttonIndex what to output.

    Block approach:

    BlockAlertView *alertView = [BlockAlertView alertWithTitle:@"Which Key?" message:nil];
    
    [alertView addButtonWithTitle:@"Button 1" block:^{
                        NSLog(@"Dog");
                    }];
    [alertView addButtonWithTitle:@"Button 2" block:^{
                        NSLog(@"Cat");
                    }];          
    [alertView addButtonWithTitle:@"Button 3" block:^{
                        NSLog(@"Shark");
                    }];
    
    [alertView show];
    

    In this case no delegate method is called, and the execution code is inside each button! So you don't need to "check for specific button title strings and do code based upon that". You need to include the code that will be executed in each button.

    I dont know if i'm clear, if you need further explanation feel free to ask.